<!DOCTYPE HTML>
<html lang="zh-CN">


<head>
    <meta charset="utf-8">
    <meta name="keywords" content="【JVM】JVM 学习笔记（第九篇）, Java,Linux,Mysql,Redis,HTTP,操作系统,计算机网络,计算机组成原理,数据结构与算法,工具使用,性能优化">
    <meta name="description" content="本网站是个人兴趣爱好，总结分享经验，记录生活点滴的平台，希望在以后的学习旅途中，走出自己的风景。">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="renderer" content="webkit|ie-stand|ie-comp">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <!-- Global site tag (gtag.js) - Google Analytics -->


    <title>【JVM】JVM 学习笔记（第九篇） | 八戒取经路</title>
    <link rel="icon" type="image/png" href="/favicon.png">

    <link rel="stylesheet" type="text/css" href="/libs/awesome/css/all.css">
    <link rel="stylesheet" type="text/css" href="/libs/materialize/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/aos/aos.css">
    <link rel="stylesheet" type="text/css" href="/libs/animate/animate.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/lightGallery/css/lightgallery.min.css">
    <link rel="stylesheet" type="text/css" href="/css/matery.css">
    <link rel="stylesheet" type="text/css" href="/css/my.css">

    <script src="/libs/jquery/jquery.min.js"></script>

<meta name="generator" content="Hexo 5.4.0">
<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
<link rel="alternate" href="/atom.xml" title="八戒取经路" type="application/atom+xml">
<link rel="stylesheet" href="/css/prism-tomorrow.css" type="text/css"></head>




<body>
    <header class="navbar-fixed">
    <nav id="headNav" class="bg-color nav-transparent">
        <div id="navContainer" class="nav-wrapper container">
            <div class="brand-logo">
                <a href="/" class="waves-effect waves-light">
                    
                    <img src="/medias/logo.png" class="logo-img" alt="LOGO">
                    
                    <span class="logo-span">八戒取经路</span>
                </a>
            </div>
            

<a href="#" data-target="mobile-nav" class="sidenav-trigger button-collapse"><i class="fas fa-bars"></i></a>
<ul class="right nav-menu">
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/" class="waves-effect waves-light">
      
      <i class="fas fa-home" style="zoom: 0.6;"></i>
      
      <span>首页</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/tags" class="waves-effect waves-light">
      
      <i class="fas fa-tags" style="zoom: 0.6;"></i>
      
      <span>标签</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/categories" class="waves-effect waves-light">
      
      <i class="fas fa-bookmark" style="zoom: 0.6;"></i>
      
      <span>分类</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/navigate" class="waves-effect waves-light">
      
      <i class="fas fa-location-arrow" style="zoom: 0.6;"></i>
      
      <span>导航</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/archives" class="waves-effect waves-light">
      
      <i class="fas fa-archive" style="zoom: 0.6;"></i>
      
      <span>归档</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/" class="waves-effect waves-light">

      
      <i class="fas fa-address-card" style="zoom: 0.6;"></i>
      
      <span>关于</span>
      <i class="fas fa-chevron-down" aria-hidden="true" style="zoom: 0.6;"></i>
    </a>
    <ul class="sub-nav menus_item_child ">
      
      <li>
        <a href="/about">
          
          <i class="fas fa-user-circle" style="margin-top: -20px; zoom: 0.6;"></i>
          
          <span>关于我</span>
        </a>
      </li>
      
      <li>
        <a href="/aboutme">
          
          <i class="fa fa-user-secret" style="margin-top: -20px; zoom: 0.6;"></i>
          
          <span>Another</span>
        </a>
      </li>
      
    </ul>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/contact" class="waves-effect waves-light">
      
      <i class="fas fa-comments" style="zoom: 0.6;"></i>
      
      <span>留言板</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/friends" class="waves-effect waves-light">
      
      <i class="fas fa-address-book" style="zoom: 0.6;"></i>
      
      <span>友情链接</span>
    </a>
    
  </li>
  
  <li>
    <a href="#searchModal" class="modal-trigger waves-effect waves-light">
      <i id="searchIcon" class="fas fa-search" title="搜索" style="zoom: 0.85;"></i>
    </a>
  </li>
</ul>


<div id="mobile-nav" class="side-nav sidenav">

    <div class="mobile-head bg-color">
        
        <img src="/medias/logo.png" class="logo-img circle responsive-img">
        
        <div class="logo-name">八戒取经路</div>
        <div class="logo-desc">
            
            本网站是个人兴趣爱好，总结分享经验，记录生活点滴的平台，希望在以后的学习旅途中，走出自己的风景。
            
        </div>
    </div>

    

    <ul class="menu-list mobile-menu-list">
        
        <li class="m-nav-item">
	  
		<a href="/" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-home"></i>
			
			首页
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/tags" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-tags"></i>
			
			标签
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/categories" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-bookmark"></i>
			
			分类
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/navigate" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-location-arrow"></i>
			
			导航
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/archives" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-archive"></i>
			
			归档
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="javascript:;">
			
				<i class="fa-fw fas fa-address-card"></i>
			
			关于
			<span class="m-icon"><i class="fas fa-chevron-right"></i></span>
		</a>
            <ul  style="background:  ;" >
              
                <li>

                  <a href="/about " style="margin-left:75px">
				  
				   <i class="fa fas fa-user-circle" style="position: absolute;left:50px" ></i>
			      
		          <span>关于我</span>
                  </a>
                </li>
              
                <li>

                  <a href="/aboutme " style="margin-left:75px">
				  
				   <i class="fa fa fa-user-secret" style="position: absolute;left:50px" ></i>
			      
		          <span>Another</span>
                  </a>
                </li>
              
            </ul>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/contact" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-comments"></i>
			
			留言板
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/friends" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-address-book"></i>
			
			友情链接
		</a>
          
        </li>
        
        
        <li><div class="divider"></div></li>
        <li>
            <a href="https://github.com/" class="waves-effect waves-light" target="_blank">
                <i class="fab fa-github-square fa-fw"></i>Fork Me
            </a>
        </li>
        
    </ul>
</div>


        </div>

        
            <style>
    .nav-transparent .github-corner {
        display: none !important;
    }

    .github-corner {
        position: absolute;
        z-index: 10;
        top: 0;
        right: 0;
        border: 0;
        transform: scale(1.1);
    }

    .github-corner svg {
        color: #0f9d58;
        fill: #fff;
        height: 64px;
        width: 64px;
    }

    .github-corner:hover .octo-arm {
        animation: a 0.56s ease-in-out;
    }

    .github-corner .octo-arm {
        animation: none;
    }

    @keyframes a {
        0%,
        to {
            transform: rotate(0);
        }
        20%,
        60% {
            transform: rotate(-25deg);
        }
        40%,
        80% {
            transform: rotate(10deg);
        }
    }
</style>

<a href="https://github.com/" class="github-corner tooltipped hide-on-med-and-down" target="_blank"
   data-tooltip="Fork Me" data-position="left" data-delay="50">
    <svg viewBox="0 0 250 250" aria-hidden="true">
        <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
        <path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
              fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
        <path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
              fill="currentColor" class="octo-body"></path>
    </svg>
</a>
        
    </nav>

</header>

    



<div class="bg-cover pd-header post-cover" style="background-image: url('/medias/featureimages/10.jpg')">
    <div class="container" style="right: 0px;left: 0px;">
        <div class="row">
            <div class="col s12 m12 l12">
                <div class="brand">
                    <h1 class="description center-align post-title">【JVM】JVM 学习笔记（第九篇）</h1>
                </div>
            </div>
        </div>
    </div>
</div>




<main class="post-container content">

    
    <link rel="stylesheet" href="/libs/tocbot/tocbot.css">
<style>
    #articleContent h1::before,
    #articleContent h2::before,
    #articleContent h3::before,
    #articleContent h4::before,
    #articleContent h5::before,
    #articleContent h6::before {
        display: block;
        content: " ";
        height: 100px;
        margin-top: -100px;
        visibility: hidden;
    }

    #articleContent :focus {
        outline: none;
    }

    .toc-fixed {
        position: fixed;
        top: 64px;
    }

    .toc-widget {
        width: 345px;
        padding-left: 20px;
    }

    .toc-widget .toc-title {
        padding: 35px 0 15px 17px;
        font-size: 1.5rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    .toc-widget ol {
        padding: 0;
        list-style: none;
    }

    #toc-content {
        padding-bottom: 30px;
        overflow: auto;
    }

    #toc-content ol {
        padding-left: 10px;
    }

    #toc-content ol li {
        padding-left: 10px;
    }

    #toc-content .toc-link:hover {
        color: #42b983;
        font-weight: 700;
        text-decoration: underline;
    }

    #toc-content .toc-link::before {
        background-color: transparent;
        max-height: 25px;

        position: absolute;
        right: 23.5vw;
        display: block;
    }

    #toc-content .is-active-link {
        color: #42b983;
    }

    #floating-toc-btn {
        position: fixed;
        right: 15px;
        bottom: 76px;
        padding-top: 15px;
        margin-bottom: 0;
        z-index: 998;
    }

    #floating-toc-btn .btn-floating {
        width: 48px;
        height: 48px;
    }

    #floating-toc-btn .btn-floating i {
        line-height: 48px;
        font-size: 1.4rem;
    }
</style>
<div class="row">
    <div id="main-content" class="col s12 m12 l9">
        <!-- 文章内容详情 -->
<div id="artDetail">
    <div class="card">
        <div class="card-content article-info">
            <div class="row tag-cate">
                <div class="col s7">
                    
                    <div class="article-tag">
                        
                            <a href="/tags/JVM/">
                                <span class="chip bg-color">JVM</span>
                            </a>
                        
                    </div>
                    
                </div>
                <div class="col s5 right-align">
                    
                </div>
            </div>

            <div class="post-info">
                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-minus fa-fw"></i>发布日期:&nbsp;&nbsp;
                    2021-04-22
                </div>
                

                

                
                <div class="info-break-policy">
                    <i class="far fa-file-word fa-fw"></i>文章字数:&nbsp;&nbsp;
                    12.2k
                </div>
                

                

                
            </div>
        </div>
        <hr class="clearfix">

        

        

        <div class="card-content article-card-content">
            <div id="articleContent">
                <h2 id="JVM结构"><a href="#JVM结构" class="headerlink" title="JVM结构"></a>JVM结构</h2><p>JVM（hotspot）结构概览如下图所示：</p>
<p><img src="https://mrbird.cc/img/QQ20200303-134536@2x.png" alt="QQ20200303-134536@2x"></p>
<p>上图中，灰色部分（Java栈，本地方法栈和程序计数器）是线程私有，不存在线程安全问题，橙色部分（方法区和堆）为线程共享区。</p>
<h2 id="类加载器"><a href="#类加载器" class="headerlink" title="类加载器"></a>类加载器</h2><p><strong>类加载器</strong>(Class Loader)负责加载class文件，class文件在文件开头有特定的标识。类加载器将class文件字节码内容加载到内存中，并将这些内容转换成<strong>方法区</strong>中的运行时数据结构。ClassLoader只负责class文件的加载，至于它是否可以运行，则由执行引擎Execution Engine决定。类加载示意图：</p>
<p><img src="https://mrbird.cc/img/QQ20200303-155915@2x.png" alt="QQ20200303-155915@2x"></p>
<p>类加载器识别的class文件除了是**.class**格式外，文件的开头还得有特殊的标识，使用文本编辑器打开一个class格式的文件：</p>
<pre class=" language-java"><code class="language-java">cafe babe <span class="token number">0000</span> <span class="token number">0034</span> <span class="token number">0010</span> 0a00 <span class="token number">0300</span> 0d07
000e <span class="token number">0700</span> 0f01 <span class="token number">0006</span> 3c69 <span class="token number">6e69</span> 743e <span class="token number">0100</span>
<span class="token number">0328</span> <span class="token number">2956</span> <span class="token number">0100</span> <span class="token number">0443</span> 6f64 <span class="token number">6501</span> <span class="token number">000f</span> 4c69
<span class="token number">6e65</span> <span class="token number">4e75</span> 6d62 <span class="token number">6572</span> <span class="token number">5461</span> 626c <span class="token number">6501</span> <span class="token number">0012</span>
4c6f <span class="token number">6361</span> 6c56 <span class="token number">6172</span> <span class="token number">6961</span> 626c <span class="token number">6554</span> <span class="token number">6162</span>
6c65 <span class="token number">0100</span> <span class="token number">0474</span> <span class="token number">6869</span> <span class="token number">7301</span> <span class="token number">0014</span> 4c63 <span class="token number">632f</span>
6d72 <span class="token number">6269</span> <span class="token number">7264</span> 2f63 <span class="token number">6173</span> 2f54 <span class="token number">6573</span> 743b
<span class="token number">0100</span> 0a53 6f75 <span class="token number">7263</span> <span class="token number">6546</span> 696c <span class="token number">6501</span> <span class="token number">0009</span>
<span class="token number">5465</span> <span class="token number">7374</span> 2e6a <span class="token number">6176</span> 610c <span class="token number">0004</span> <span class="token number">0005</span> <span class="token number">0100</span>
<span class="token number">1263</span> <span class="token number">632f</span> 6d72 <span class="token number">6269</span> <span class="token number">7264</span> 2f63 <span class="token number">6173</span> 2f54
<span class="token number">6573</span> <span class="token number">7401</span> <span class="token number">0010</span> 6a61 <span class="token number">7661</span> 2f6c 616e <span class="token number">672f</span>
4f62 6a65 <span class="token number">6374</span> <span class="token number">0021</span> <span class="token number">0002</span> <span class="token number">0003</span> <span class="token number">0000</span> <span class="token number">0000</span>
<span class="token number">0001</span> <span class="token number">0001</span> <span class="token number">0004</span> <span class="token number">0005</span> <span class="token number">0001</span> <span class="token number">0006</span> <span class="token number">0000</span> <span class="token number">002f</span>
<span class="token number">0001</span> <span class="token number">0001</span> <span class="token number">0000</span> <span class="token number">0005</span> 2ab7 <span class="token number">0001</span> b100 <span class="token number">0000</span>
<span class="token number">0200</span> <span class="token number">0700</span> <span class="token number">0000</span> <span class="token number">0600</span> <span class="token number">0100</span> <span class="token number">0000</span> <span class="token number">0300</span> <span class="token number">0800</span>
<span class="token number">0000</span> 0c00 <span class="token number">0100</span> <span class="token number">0000</span> <span class="token number">0500</span> <span class="token number">0900</span> 0a00 <span class="token number">0000</span>
<span class="token number">0100</span> <span class="token number">0b00</span> <span class="token number">0000</span> <span class="token number">0200</span> 0c
</code></pre>
<p>这个特定的标识就是十六进制字符<strong>cafe babe</strong>。</p>
<h3 id="类加载器分类"><a href="#类加载器分类" class="headerlink" title="类加载器分类"></a>类加载器分类</h3><p>类加载器分为4种：</p>
<h4 id="启动类加载器"><a href="#启动类加载器" class="headerlink" title="启动类加载器"></a>启动类加载器</h4><p>启动类加载器BootstrapClassLoader也叫根加载器，是虚拟机自带的加载器，底层由C++实现，用于加载<code>$JAVA_HOME/jre/lib/rt.jar</code>包内的class文件。rt.jar是Java基础类库，包含Java运行环境所需的基础类：</p>
<p><img src="https://mrbird.cc/img/QQ20200303-161919@2x.png" alt="QQ20200303-161919@2x"></p>
<p>举个例子：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        Object object <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Object</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>object<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p><code>Object</code>为Java自带的类，运行结果如下：</p>
<pre class=" language-java"><code class="language-java">null
</code></pre>
<p>并没有返回预期的BootstrapClassLoader，这是因为BootstrapClassLoader底层是由C++实现的，并非Java实现。</p>
<h4 id="拓展类加载器"><a href="#拓展类加载器" class="headerlink" title="拓展类加载器"></a>拓展类加载器</h4><p>拓展类加载器ExtClassLoader是虚拟机自带的加载器，由Java语言实现，用于加载<code>$JAVA_HOME/jre/lib/ext/**.jar</code>目录下的class文件：</p>
<p><img src="https://mrbird.cc/img/QQ20200303-162428@2x.png" alt="QQ20200303-162428@2x"></p>
<p>这部分主要是Java在迭代过程中，一些拓展的功能。</p>
<p>比如：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        ZipInfo zipInfo <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ZipInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>zipInfo<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p><code>ZipInfo</code>是<code>$JAVA_HOME/jre/lib/ext/zipfs.jar</code>包里的一个类，程序运行结果如下：</p>
<pre class=" language-java"><code class="language-java">sun<span class="token punctuation">.</span>misc<span class="token punctuation">.</span>Launcher$ExtClassLoader<span class="token annotation punctuation">@5e2de80c</span>
</code></pre>
<h4 id="应用程序类加载器"><a href="#应用程序类加载器" class="headerlink" title="应用程序类加载器"></a>应用程序类加载器</h4><p>应用程序类加载器AppClassLoader是虚拟机自带的加载器，用于加载当前应用的classpath的所有类，也就是我们自己写的那些Java代码，比如：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>Test<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>程序运行结果：</p>
<pre class=" language-java"><code class="language-java">sun<span class="token punctuation">.</span>misc<span class="token punctuation">.</span>Launcher$AppClassLoader<span class="token annotation punctuation">@18b4aac2</span>
</code></pre>
<h4 id="用户自定义加载器"><a href="#用户自定义加载器" class="headerlink" title="用户自定义加载器"></a>用户自定义加载器</h4><p>除了使用上面三种JVM自带的类加载器外，我们也可以通过继承Java.lang.ClassLoader抽象类自定义一个类加载器。</p>
<p>这四种类加载器的关系如下图所示：</p>
<p><img src="https://mrbird.cc/img/QQ20200303-165603@2x.png" alt="QQ20200303-165603@2x"></p>
<p>它们的关系是一种父子关系，我们可以通过代码验证：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        Class<span class="token operator">&lt;</span>Test<span class="token operator">></span> testClass <span class="token operator">=</span> Test<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>testClass<span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>testClass<span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getParent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>testClass<span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getParent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getParent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>程序运行结果如下所示：</p>
<pre class=" language-java"><code class="language-java">sun<span class="token punctuation">.</span>misc<span class="token punctuation">.</span>Launcher$AppClassLoader<span class="token annotation punctuation">@18b4aac2</span>
sun<span class="token punctuation">.</span>misc<span class="token punctuation">.</span>Launcher$ExtClassLoader<span class="token annotation punctuation">@61bbe9ba</span>
null
</code></pre>
<h3 id="类加载步骤"><a href="#类加载步骤" class="headerlink" title="类加载步骤"></a>类加载步骤</h3><p>类的加载过程分为<strong>三个</strong>步骤：</p>
<h4 id="加载Loading"><a href="#加载Loading" class="headerlink" title="加载Loading"></a>加载Loading</h4><p>通过一个类的全类名获取其二进制字节流，将这个二进制流代表的静态存储结构转化为方法区的运行时数据结构，然后在内存中生成一个代表这个类的java.lang.Class对象，作为方法区中这个类的各种数据的访问入口。</p>
<h4 id="链接Linking"><a href="#链接Linking" class="headerlink" title="链接Linking"></a>链接Linking</h4><p>该过程又可以分为三个阶段：<strong>验证Verfication</strong>，<strong>准备Preparation</strong>和<strong>解析Resolution</strong>）。</p>
<ul>
<li><p>验证阶段用于确保加载的Class文件的字节流包含的信息是否符合虚拟机要求，保证其正确性合法性，javac的过程安装java虚拟机规范进行编译，编译后的字节码，在链接阶段的验证阶段，又会根据java虚拟机规范去校验字节码的格式，都是为了安全；</p>
</li>
<li><p>准备阶段为类变量（static修饰的变量）分配内存并根据对象类型设置相应的默认初始值（比如int类型为0，Integer类型为null）。这里不包含常量，因为常量在编译的时候分配，准备阶段会显示初始化。类的实例变量不会在这个阶段准备初始化。</p>
</li>
<li><p>解析阶段用于将符号引用转换为直接引用。</p>
<p>观察如下代码：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        String str <span class="token operator">=</span> <span class="token string">"hello"</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>str<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>使用javap -v命令查看其字节码：</p>
<p><img src="https://mrbird.cc/img/QQ20200615-171009@2x.png" alt="QQ20200615-171009@2x"></p>
<p>可以看到常量池中有许多符号引用（比如#2），解析阶段就是将其解析为直接引用（比如#2表示字符串常量hello）的过程。</p>
</li>
</ul>
<h4 id="初始化Initialization"><a href="#初始化Initialization" class="headerlink" title="初始化Initialization"></a>初始化Initialization</h4><ul>
<li><p>该阶段就是执行类的构造器方法<code>&lt;clinit&gt;()</code>的过程 ；该方法并不是类的构造器，不需要我们自己定义，是javac编译器自动搜集类中的所有类变量的赋值动作和静态代码块中的语句合并而来；</p>
<p>创建一个简单的类，包含一个名为aaa的类变量：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span> aaa <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>

    <span class="token keyword">static</span> <span class="token punctuation">{</span>
        aaa <span class="token operator">=</span> <span class="token number">200</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>Test<span class="token punctuation">.</span>aaa<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>然后通过IDEA的jclasslib插件查看该类的class文件对应的字节码：</p>
<p><img src="https://mrbird.cc/img/QQ20200615-143009@2x.png" alt="QQ20200615-143009@2x"></p>
<p>可以看到上面所说的构造器方法<code>&lt;clinit&gt;()</code>，指令的操作就是为所有类变量赋值以及静态代码块中的操作。换句话说，如果一个类不包含类变量和静态代码块，那么它的字节码中就不会有构造器方法<code>&lt;clinit&gt;()</code>。</p>
</li>
<li><p>构造器方法中的指令按照语句在源代码中出现的顺序执行；</p>
<p>观察如下代码：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span> aaa <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>

    <span class="token keyword">static</span> <span class="token punctuation">{</span>
        aaa <span class="token operator">=</span> <span class="token number">200</span><span class="token punctuation">;</span>
        bbb <span class="token operator">=</span> <span class="token number">300</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span> bbb <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>Test<span class="token punctuation">.</span>bbb<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>上面程序输出结果为2，因为构造器方法中的指令按照语句在源代码中出现的顺序执行，查看构造器方法<code>&lt;clinit&gt;()</code>指令来证明这一点：</p>
<p><img src="https://mrbird.cc/img/QQ20200615-143747@2x.png" alt="QQ20200615-143747@2x"></p>
<p>这里还有一个细节，就是为什么在静态代码块下面才定义的类变量bbb，在静态代码块中可以进行修改呢？这就是Linking阶段中准备阶段所做的事情，准备阶段为类变量（static修饰的变量）分配内存并根据对象类型设置相应的默认初始值。这个时候bbb已经被分配并赋予默认初始值了，所以static块中可以使用该变量（换句话说，实例变量不行）。</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span> aaa <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>

    <span class="token keyword">static</span> <span class="token punctuation">{</span>
        aaa <span class="token operator">=</span> <span class="token number">200</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>Test<span class="token punctuation">.</span>bbb<span class="token punctuation">)</span><span class="token punctuation">;</span>
        bbb <span class="token operator">=</span> <span class="token number">300</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span> bbb <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>Test<span class="token punctuation">.</span>bbb<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>上面输出0 2。</p>
<p>下面代码直接编译失败：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span> aaa <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>

    <span class="token keyword">static</span> <span class="token punctuation">{</span>
        aaa <span class="token operator">=</span> <span class="token number">200</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>Test<span class="token punctuation">.</span>bbb<span class="token punctuation">)</span><span class="token punctuation">;</span>
        bbb <span class="token operator">=</span> <span class="token number">300</span><span class="token punctuation">;</span>
        ccc <span class="token operator">=</span> <span class="token number">400</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span> bbb <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> ccc <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>Test<span class="token punctuation">.</span>bbb<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p><img src="https://mrbird.cc/img/QQ20200615-144259@2x.png" alt="QQ20200615-144259@2x"></p>
<p>因为ccc还没分配初始化呢。</p>
</li>
<li><p>若该类包含父类，那么JVM会保证父类的<code>&lt;clinit&gt;()</code>先执行完毕；</p>
</li>
<li><p>虚拟机会保证一个类的<code>&lt;clinit&gt;()</code>方法在多线程下被同步加锁。</p>
<p>观察如下代码：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        Runnable r <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token punctuation">{</span>
            System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>Thread<span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"开始"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">new</span> <span class="token class-name">Hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>Thread<span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"结束"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>

        <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span>r<span class="token punctuation">,</span> <span class="token string">"线程1"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span>r<span class="token punctuation">,</span> <span class="token string">"线程2"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>

<span class="token keyword">class</span> <span class="token class-name">Hello</span> <span class="token punctuation">{</span>
    <span class="token keyword">static</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>Thread<span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"初始化当前类"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>

            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>程序启动后，main线程启动两个子线程，控制台输出如下：</p>
<pre class=" language-java"><code class="language-java">线程<span class="token number">1</span>开始
线程<span class="token number">2</span>开始
线程<span class="token number">1</span>初始化当前类
</code></pre>
<p>然后程序block住，这说明了虚拟机会保证一个类的<code>&lt;clinit&gt;()</code>方法在多线程下被同步加锁。</p>
</li>
</ul>
<h3 id="双亲委派机制"><a href="#双亲委派机制" class="headerlink" title="双亲委派机制"></a>双亲委派机制</h3><p>聊到类加载器不得不提的另一个话题就是<strong>双亲委派机制</strong>，在了解什么是双亲委派机制之前，我们先来看个例子：</p>
<p>在src/main/java目录下新建java.lang包，然后在该包下新建一个String类：</p>
<p><img src="https://mrbird.cc/img/QQ20200303-170626@2x.png" alt="QQ20200303-170626@2x"></p>
<p>String类的代码如下所示：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">package</span> java<span class="token punctuation">.</span>lang<span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">String</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"helo"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>程序输出结果：</p>
<pre class=" language-java"><code class="language-java">错误<span class="token operator">:</span> 在类 java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>String 中找不到 main 方法<span class="token punctuation">,</span> 请将 main 方法定义为<span class="token operator">:</span>
   <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span>
否则 JavaFX 应用程序类必须扩展javafx<span class="token punctuation">.</span>application<span class="token punctuation">.</span>Application
</code></pre>
<p>所谓的双亲委派机制就是：当一个类收到了类加载请求，他首先不会尝试自己去加载这个类，而是把这个请求委派给父类去完成，每一个层次类加载器都是如此。只有当父类加载器反馈自己无法完成这个请求的时候（在它的加载路径下没有找到所需加载的Class），子类加载器才会尝试自己去加载。</p>
<p>所以上面的例子中，AppClassLoader委派给它的父类ExtClassLoader去加载，ExtClassLoader又委托给它的父类BootstrapClassLoader去加载。BootstrapClassLoader从它的加载路径<code>$JAVA_HOME/jre/lib/rt.jar</code>下找到了<code>java.lang.String</code>类，即rt.jar包下的String类，而该类里并没有main方法，所以便抛出了如上异常。</p>
<p>采用双亲委派的一个好处是：就如上面所说，不管是哪个加载器加载这个类，最终都是委托给顶层的启动类加载器进行加载，这样就保证了使用不同的类加载器最终得到的都是同样一个String对象，所以我们自定义的Java类并不会污染JDK自带的那些类（即使全类名一样），这种保护机制也叫沙箱安全机制。</p>
<h2 id="程序计数器"><a href="#程序计数器" class="headerlink" title="程序计数器"></a>程序计数器</h2><p><strong>程序计数器</strong>(Program Counter Register)又叫PC寄存器。每个线程都有一个程序计数器，是线程私有的。它是一个指针，指向方法区中的方法字节码，用来存储指向下一条指令的地址，也即将要执行的指令代码，由执行引擎读取下一条指令，是一个非常小的内存空间，几乎可以忽略不记。</p>
<p><img src="https://mrbird.cc/img/QQ20200615-183140@2x.png" alt="QQ20200615-183140@2x"></p>
<p>如果执行的是一个Native方法，那这个计数器的值为undefied。</p>
<p>为什么需要程序计数器呢？因为CPU需要不停地切换各个线程，有了程序计数器后，当CPU切换回来后，我们就可以知道接着从哪开始继续执行程序，举个例子，现有如下代码：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> b <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> c <span class="token operator">=</span> a <span class="token operator">+</span> b<span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>查看其字节码：</p>
<p><img src="https://mrbird.cc/img/QQ20200615-184326@2x.png" alt="QQ20200615-184326@2x"></p>
<p>假如当前线程的程序计数器存储的指令地址为6，这时候CPU切换到别的线程中处理工作；一段时间后，当前线程重新获取了CPU时间片继续执行时，根据程序计数器存的6就知道，当前需要执行iadd（即a+b操作）指令。执行引擎会将这条指令翻译为机器指令，然后CPU执行该运算操作。</p>
<h2 id="虚拟机栈（Java栈）"><a href="#虚拟机栈（Java栈）" class="headerlink" title="虚拟机栈（Java栈）"></a>虚拟机栈（Java栈）</h2><p>虚拟机栈也称为Java栈，每个线程在创建的时候都会创建一个虚拟机栈，其内部保存一个个栈帧（Stack Frame），对应着一次次的Java方法调用。和PC寄存器一样，虚拟机栈的生命周期和线程一致。虚拟机栈主管Java程序的运行，它保存方法的局部变量（8种基本数据类型，对象引用地址）、部分结果，并参与方法的调用和返回。</p>
<p>虚拟机栈示意图如下所示：</p>
<p><img src="https://mrbird.cc/img/QQ20200618-091650@2x.png" alt="QQ20200618-091650@2x"></p>
<p>JVM对虚拟机栈的操作只有压栈（入栈）和出栈操作，遵循FILO原则；在一个活动线程中，一个时间点只会有一个活动的栈帧，即当前正在执行方法对应的栈帧（当前栈帧）；如果一个方法调用了另一个方法，那么对应的新的栈帧将会被创建出来，放在栈顶，成为新的当前栈帧。</p>
<p>编写一个简单代码，使用debug的方式来观察入栈和出栈操作：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">new</span> <span class="token class-name">Test</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">method1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">method1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"method1 start"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">method2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"method1 finish"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">method2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"method2 start"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">method3</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"method2 finish"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">method3</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"method3 start"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">method4</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"method3 finish"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">method4</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"method4 start"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"method4 finish"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p><img src="https://mrbird.cc/img/2020-06-18%2009.33.53.gif" alt="2020-06-18 09.33.53.gif"></p>
<p>可以看到，执行main方法后，main方法首先入栈，接着调用method1方法，method1方法入栈；method1调用method2，method2入栈；method2调用method3，method3入栈；method3调用method4，method4入栈；method4执行结束，正常退出，method4出栈；method4出栈后，当前栈帧变为method3对应的栈帧；method3执行结束正常退出，method3出栈……以此类推，最终main方法执行结束出栈，程序结束。</p>
<p><strong>Java方法执行结束正常退出和抛出异常这两种情况会导致栈帧被弹出（退出）</strong>。</p>
<h3 id="虚拟机栈大小调整"><a href="#虚拟机栈大小调整" class="headerlink" title="虚拟机栈大小调整"></a>虚拟机栈大小调整</h3><p>Java虚拟机规范允许虚拟机栈的大小固定不变或者动态扩展。</p>
<ul>
<li>固定情况下：如果线程请求分配的栈容量超过Java虚拟机允许的最大容量，则抛出StackOverflowError异常；</li>
<li>可动态扩展情况下：尝试扩展的时候无法申请到足够的内存；或者在创建新的线程的时候没有足够的内存去创建对应的虚拟机栈，则会抛出OutOfMemoryError异常。</li>
</ul>
<p>不同平台的虚拟机栈默认大小不同：</p>
<ul>
<li>Linux/x64 (64-bit): 1024 KB</li>
<li>macOS (64-bit): 1024 KB</li>
<li>Oracle Solaris/x64 (64-bit): 1024 KB</li>
<li>Windows: 默认值取决于虚拟内存。</li>
</ul>
<p>我们可以通过<code>-Xss</code>（<code>-XX:ThreadStackSize</code>简写）设置虚拟机栈大小，默认单位为字节。也可以通过k或者K指定单位为KB，m或M指定单位为MB，g或G指定单位为GB。下面这组配置都是将虚拟机栈大小设置为1024KB：</p>
<pre class=" language-java"><code class="language-java"><span class="token operator">-</span>Xss1m
<span class="token operator">-</span>Xss1024k
<span class="token operator">-</span>Xss1048576
</code></pre>
<p>虚拟机栈越大，方法调用深度越深，举个例子：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span> count <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>count<span class="token punctuation">)</span><span class="token punctuation">;</span>
        count<span class="token operator">++</span><span class="token punctuation">;</span>
        <span class="token function">main</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>在macOS平台下，虚拟机栈的默认大小为1024KB，程序运行结果如下：</p>
<pre class=" language-java"><code class="language-java"><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token number">10817</span>
<span class="token number">10818</span>
<span class="token number">10819</span>
<span class="token number">10820</span>
<span class="token number">10821</span>
<span class="token number">10822</span>
<span class="token number">10823</span>
<span class="token number">10824</span>
<span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span> java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>instrument ASSERTION FAILED <span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span><span class="token operator">:</span> <span class="token string">"!errorOutstanding"</span> with message transform method call failed at JPLISAgent<span class="token punctuation">.</span>c line<span class="token operator">:</span> <span class="token number">844</span>
Exception in thread <span class="token string">"main"</span> java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>StackOverflowError
</code></pre>
<p>程序输出10824后抛出StackOverflowError；</p>
<p>我们通过<code>-Xss200k</code>命令将虚拟机栈大小调整为200KB再观察输出结果：</p>
<pre class=" language-java"><code class="language-java"><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token number">1214</span>
<span class="token number">1215</span>
<span class="token number">1216</span>
<span class="token number">1217</span>
<span class="token number">1218</span>
<span class="token number">1219</span>
<span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span> java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>instrument ASSERTION FAILED <span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span><span class="token operator">:</span> <span class="token string">"!errorOutstanding"</span> with message transform method call failed at JPLISAgent<span class="token punctuation">.</span>c line<span class="token operator">:</span> <span class="token number">844</span>
<span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span> java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>instrument ASSERTION FAILED <span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span><span class="token operator">:</span> <span class="token string">"!errorOutstanding"</span> with message transform method call failed at JPLISAgent<span class="token punctuation">.</span>c line<span class="token operator">:</span> <span class="token number">844</span>
<span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span> java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>instrument ASSERTION FAILED <span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span><span class="token operator">:</span> <span class="token string">"!errorOutstanding"</span> with message transform method call failed at JPLISAgent<span class="token punctuation">.</span>c line<span class="token operator">:</span> <span class="token number">844</span>
Exception in thread <span class="token string">"main"</span> java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>StackOverflowError
</code></pre>
<p>可以看到，方法调用深度明显变小了。</p>
<h3 id="栈帧内部结构"><a href="#栈帧内部结构" class="headerlink" title="栈帧内部结构"></a>栈帧内部结构</h3><p>每个栈帧包含5个组成部分：局部变量表（Local Variables）、操作数栈（Operand Stack）、动态链接（Dynamic Linking）、方法返回地址（Return Address）和一些附加信息：</p>
<p><img src="https://mrbird.cc/img/QQ20200618-140408@2x.png" alt="QQ20200618-140408@2x"></p>
<h4 id="局部变量表"><a href="#局部变量表" class="headerlink" title="局部变量表"></a>局部变量表</h4><p>局部变量表是一个数字数组，用于存储方法参数和方法体内的局部变量。</p>
<p>下面Test类包含hello静态方法：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">hello</span><span class="token punctuation">(</span>String name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        Date date <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> count <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>使用<code>javap -v</code>命令查看其字节码：</p>
<p><img src="https://mrbird.cc/img/QQ20200618-143216@2x.png" alt="QQ20200618-143216@2x"></p>
<p>非静态方法的局部变量表和静态方法相比，多了个this对象（即当前类）：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">halo</span><span class="token punctuation">(</span>String name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        Date date <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> count <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p><img src="https://mrbird.cc/img/QQ20200618-143527@2x.png" alt="QQ20200618-143527@2x"></p>
<p>可以看到，非静态方法的局部变量表首位就存放了this对象，这也是静态方法内无法使用this的原因（因为静态方法的局部变量表中没有this对象）。</p>
<p>局部变量表数组容量的大小在编译期就可以唯一确定下来，并保存在方法的Code属性的maximum locacl variables数据项中，就拿上面Test类的hello方法来说，其字节码里已经指明了局部变量表的大小：</p>
<p><img src="https://mrbird.cc/img/QQ20200618-145018@2x.png" alt="QQ20200618-145018@2x"></p>
<p>通过jclasslib插件也可以看到局部变量表的大小：</p>
<p><img src="https://mrbird.cc/img/QQ20200618-145126@2x.png" alt="QQ20200618-145126@2x"></p>
<p>局部变量表的最基本单元是变量槽（Slot）。局部变量表中32位以内的数据类型（除long和double外）只占用一个slot，64位类型（long和double）占用两个slot。举个例子：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">hello</span><span class="token punctuation">(</span>String name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        Date date <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">long</span> number <span class="token operator">=</span> 200L<span class="token punctuation">;</span>
        <span class="token keyword">double</span> salary <span class="token operator">=</span> <span class="token number">6000.0</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> count <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p><img src="https://mrbird.cc/img/QQ20200618-150204@2x.png" alt="QQ20200618-150204@2x"></p>
<p>此外，通过局部变量表包含的信息，我们还可以得出局部变量的作用范围。举个例子，当前有如下代码：</p>
<p><img src="https://mrbird.cc/img/QQ20200618-150846@2x.png" alt="QQ20200618-150846@2x"></p>
<p>查看其字节码：</p>
<p><img src="https://mrbird.cc/img/QQ20200618-151022@2x.png" alt="QQ20200618-151022@2x"></p>
<p>以方法参数name为例，查看LocalVariableTable，name参数对应的Start列的值为0，表示其在第0行字节码指令处生效（通过LineNumberTable我们可以知道，第0行字节码指令对应程序中的第6行代码）；Length列的值为3，说明name参数的有效作用域长度为3，因为name是在第0行字节码指令处生效的，所以name在0 ~ 2行字节码指令范围内有效（通过LineNumberTable的对应关系，我们也可以知道name在我们的代码中作用域范围为第6行到第7行）。</p>
<p>局部变量表的槽位是可以重复利用的，如果一个局部变量过了其作用域，那么在其作用域之后申明的新的局部变量很有可能会复用过期局部变量的槽位。举个例子，现有如下代码：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">hello</span><span class="token punctuation">(</span>String name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
            System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">int</span> b <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>查看其局部变量表：</p>
<p><img src="https://mrbird.cc/img/QQ20200618-160223@2x.png" alt="QQ20200618-160223@2x"></p>
<p>可以看到局部变量a和b的槽位都是1，说明槽位重复利用了。这是因为在定义局部变量b的时候，局部变量a已经出了作用域失效销毁了，但是局部变量表的槽位已经开辟了，所以局部变量b直接重复利用索引为1的槽位。</p>
<h4 id="操作数栈"><a href="#操作数栈" class="headerlink" title="操作数栈"></a>操作数栈</h4><p>每一个独立的栈帧中除了包含局部变量表外，还包含一个FILO的操作数栈，用于保存计算过程中的中间结果，同时作为计算过程中变量临时的存储空间。每个操作数栈都有一个明确的深度，在编译期已经确定下来：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> b <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> c <span class="token operator">=</span> a <span class="token operator">+</span> b<span class="token punctuation">;</span>
        <span class="token keyword">return</span> c<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>查看其字节码：</p>
<p><img src="https://mrbird.cc/img/QQ20200618-165953@2x.png" alt="QQ20200618-165953@2x"></p>
<p>栈中的任何一个元素都可以是任意的Java数据类型，32bit的类型占用一个栈深度，64bit的类型占用两个栈单位深度：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>查看其字节码：</p>
<p><img src="https://mrbird.cc/img/QQ20200619-092727@2x.png" alt="QQ20200619-092727@2x"></p>
<p>操作数栈深度为1。</p>
<p>将代码的局部变量a类型改为64bit的double类型：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">double</span> b <span class="token operator">=</span> <span class="token number">1.0</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p><img src="https://mrbird.cc/img/QQ20200619-093123@2x.png" alt="QQ20200619-093123@2x"></p>
<p>操作数栈深度为2。</p>
<p>操作数栈在方法的执行过程中，根据字节码指令往栈中写入数据或提取数据，即入栈和出栈操作。虽然栈是用数组实现的，但根据栈的特性，对栈中数据访问不能通过索引，而是只能通过标准的入栈和出栈操作来完成一次数据访问。</p>
<p>下面通过一个例子来感受PC寄存器，局部变量表和操作数栈是如何相互配合完成一次方法的执行，代码如下所示：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">15</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> b <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> c <span class="token operator">=</span> a <span class="token operator">+</span> b<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>在查看字节码指令之前，先记录下几个入栈出栈的字节码指令含义：</p>
<ul>
<li>当int取值 -1 ~ 5 采用iconst指令入栈；</li>
<li>取值 -128 ~ 127（byte有效范围）采用bipush指令入栈；</li>
<li>取值 -32768 ~ 32767（short有效范围）采用sipush指令入栈；</li>
<li>取值 -2147483648 ~ 2147483647（int有效范围）采用ldc指令入栈；</li>
<li>istore，栈顶元素出栈，保存到局部变量表中；</li>
<li>iload，从局部变量表中加载数据入栈。</li>
</ul>
<p>更多字节码指令含义后续深入学习Java虚拟机字节码指令再说🌚。</p>
<p>上面方法对应的字节码如下：</p>
<p><img src="https://mrbird.cc/img/QQ20200619-100036@2x.png" alt="QQ20200619-100036@2x"></p>
<p>指令执行过程中，PC寄存器，局部变量表和操作数栈状态如下图所示：</p>
<p><img src="https://mrbird.cc/img/QQ20200619-102230@2x.png" alt="QQ20200619-102230@2x"></p>
<p><img src="https://mrbird.cc/img/QQ20200619-102507@2x.png" alt="QQ20200619-102507@2x"></p>
<p><img src="https://mrbird.cc/img/QQ20200619-102909@2x.png" alt="QQ20200619-102909@2x"></p>
<p><img src="https://mrbird.cc/img/QQ20200619-103226@2x.png" alt="QQ20200619-103226@2x"></p>
<p><img src="https://mrbird.cc/img/QQ20200619-103556@2x.png" alt="QQ20200619-103556@2x"></p>
<p><img src="https://mrbird.cc/img/QQ20200619-103957@2x.png" alt="QQ20200619-103957@2x"></p>
<p><img src="https://mrbird.cc/img/QQ20200619-104225@2x.png" alt="QQ20200619-104225@2x"></p>
<p><img src="https://mrbird.cc/img/QQ20200619-104405@2x.png" alt="QQ20200619-104405@2x"></p>
<p>如果被调用的方法带有返回值的话，其返回值会被压入当前栈帧的操作数栈中。</p>
<h4 id="动态链接"><a href="#动态链接" class="headerlink" title="动态链接"></a>动态链接</h4><p>在Java源文件被编译成字节码文件时，所有的变量和方法引用都作为符号引用保存在class文件的常量池里，动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用，比如：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"hello"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>其字节码中的常量池如下：</p>
<p><img src="https://mrbird.cc/img/QQ20200619-141303@2x.png" alt="QQ20200619-141303@2x"></p>
<p>比如符号#27就表示为一个打印流。</p>
<h4 id="方法返回地址"><a href="#方法返回地址" class="headerlink" title="方法返回地址"></a>方法返回地址</h4><p>存放调用该方法的pc寄存器的值。一个方法的结束分为以下两种方式：</p>
<ul>
<li>正常执行结束；</li>
<li>出现未处理异常，非正常退出。</li>
</ul>
<p>无论是哪种方式退出，在方法退出后都返回到该方法被调用的位置。方法正常退出时，调用者的pc寄存器的值作为返回地址，即调用该方法的指令的下一条指令地址；异常退出时，返回地址需要通过异常表来确定。</p>
<h4 id="一些附加信息"><a href="#一些附加信息" class="headerlink" title="一些附加信息"></a>一些附加信息</h4><p>比如对程序调式提供的支持信息。</p>
<h2 id="本地方法接口"><a href="#本地方法接口" class="headerlink" title="本地方法接口"></a>本地方法接口</h2><p>本地方法接口(Native Interface)的作用是融合不同的编程语言为Java所用，它的初衷是融合C/C++程序。Java诞生的时候是 C/C++横行的时候，要想立足，必须调用 C/C++程序，于是就在内存中专门开辟了一块区域处理标记为native的代码。</p>
<p>比如查看java.lang.Thread类源码就会发现当中存在许多native方法：</p>
<p><img src="https://mrbird.cc/img/QQ20200623-164809@2x.png" alt="QQ20200623-164809@2x"></p>
<p>native方法没有方法体（因为不是Java实现），所以看上去像是“接口”一样，故得名本地方法接口。</p>
<h2 id="本地方法栈"><a href="#本地方法栈" class="headerlink" title="本地方法栈"></a>本地方法栈</h2><p>如前所述，虚拟机栈用于管理Java方法的调用，而本地方法栈则是用于管理本地方法的调用。</p>
<h2 id="堆（Heap）"><a href="#堆（Heap）" class="headerlink" title="堆（Heap）"></a>堆（Heap）</h2><p>堆（Heap）一个JVM实例只存在一个堆内存，堆内存的大小是可以调节的。堆中保存着所有引用类型的真实信息，以方便执行器执行。堆在逻辑上分为三个区域：</p>
<p>Java7：</p>
<p><img src="https://mrbird.cc/img/QQ20200305-103335@2x.png" alt="QQ20200305-103335@2x"></p>
<p>Java8：</p>
<p><img src="https://mrbird.cc/img/QQ20200305-103619@2x.png" alt="QQ20200305-103619@2x"></p>
<p>可以看到，在Java7时代，堆分为新生区（新生区包含伊甸园区和幸存区，幸存区又包含幸存者0区和幸存者1区。此外，幸存者0区又称为From区，幸存者1区又称为To区，From区和To区并不是固定的，复制之后交互，谁空谁是To），养老区和永久代；在Java8中，永久代已经被移除，被一个称为元空间的区域所取代。元空间的本质和永久代类似。</p>
<p>元空间与永久代之间最大的区别在于：永久代使用的JVM的堆内存，但是java8以后的元空间并不在虚拟机中而是使用本机物理内存（所以在上图中，我用虚线表示）。</p>
<p>堆之所以要分区是因为：Java程序中不同对象的生命周期不同，70%~99%对象都是临时对象，这类对象在新生区“朝生夕死”。如果没有分区，GC时搜集垃圾需要对整个堆内存进行扫描；分区后，回收这些“朝生夕死”的对象，只需要在小范围的区域中（新生区）搜集垃圾。所以，分区的唯一理由就是为了优化GC性能。</p>
<h3 id="堆空间对象分配过程"><a href="#堆空间对象分配过程" class="headerlink" title="堆空间对象分配过程"></a>堆空间对象分配过程</h3><p>下面通过一个例子来讲述这几个区的交互逻辑：</p>
<p><strong>1.几乎任何新的对象都是在伊甸园区被new出来创建，刚开始的时候两个幸存者区和养老区都是空的：</strong></p>
<p><img src="https://mrbird.cc/img/QQ20200305-105423@2x_meitu_1.jpg" alt="QQ20200305-105423@2x"></p>
<p><strong>2.随着对象的不断创建，伊甸园区空间逐渐被填满：</strong></p>
<p><img src="https://mrbird.cc/img/QQ20200305-110220@2x_meitu_2.jpg" alt="QQ20200305-110220@2x_meitu_2.jpg"></p>
<p><strong>3.这时候将触发一次Minor GC（Young GC），删除未引用的对象，GC剩下来的还存在引用的对象将移动到幸存者0区，然后清空伊甸园区：</strong></p>
<p><img src="https://mrbird.cc/img/QQ20200305-110720@2x.png" alt="QQ20200305-110720@2x"></p>
<p><strong>4.随着对象的创建，伊甸园区空间又满了，再一次触发Minor GC，删除未引用的对象，留下存在引用的对象。这次和上一次Minor GC有些不同，这轮GC留下的对象将被移动到幸存者1区，并且上一轮GC留下来的存储在幸存者0区的对象年龄递增并移动到幸存者1区。当所有幸存对象都移动到幸存者1区后，幸存者0区和伊甸园区空间清除：</strong></p>
<p><img src="https://mrbird.cc/img/QQ20200305-111503@2x.png" alt="QQ20200305-111503@2x"></p>
<p><strong>5.随着对象的创建伊甸园区空间再一次满了，触发了第三次Minor GC，这一次幸存区空间将发生互换，GC留下来的幸存者将移动到幸存者0区，幸存者1区的幸存对象年龄递增后也移动到幸存者0区，然后伊甸园区和幸存者1区的空间被清除：</strong></p>
<p><img src="https://mrbird.cc/img/QQ20200305-112210@2x.png" alt="QQ20200305-112210@2x"></p>
<p><strong>6.随着Minor GC的不断发生，幸存对象在两个幸存区不断地交换存储，年龄也不断递增。如此反反复复之后，当幸存对象的年龄达到指定的阈值（这个例子中是8，由JVM参数MaxTenuringThreshold决定）后，它们将被移动到养老区：</strong></p>
<p><img src="https://mrbird.cc/img/QQ20200305-112448@2x.png" alt="QQ20200305-112448@2x"></p>
<p><strong>7.随着上述过程的不断出现，当养老区快满时，将触发Major GC（Full GC）进行养老区的内存清理。若养老区执行了GC之后发现依然无法进行对象的保存，就会产生OOM异常。</strong></p>
<p>一个对象被放置到养老区除了它的年龄达到阈值外，以下几种情况也会使得该对象直接被放置到养老区：</p>
<ol>
<li>对象创建后，无法放置到伊甸园区（比如伊甸园区的大小为10m，新的对象大小为11m，伊甸园区不够放，触发YGC。YGC后伊甸园区被清空，但还是无法容下11m的“超大对象”，所以直接放置到养老区。当然如果养老区放置不下则会触发FGC，FGC后还放不下则OOM）；</li>
<li>YGC后，对象无法放置到幸存者To区也会直接晋升到养老区；</li>
<li>如果幸存区中相同年龄的所有对象大小大于幸存区空间的一半，年龄大于或等于这些对象年龄的对象可以直接进入养老区，无需等到年龄阈值。</li>
</ol>
<h3 id="堆参数"><a href="#堆参数" class="headerlink" title="堆参数"></a>堆参数</h3><p>以JDK1.8+HotSpot为例，常用的可调整的堆参数有：</p>
<table>
<thead>
<tr>
<th align="left">参数</th>
<th align="left">含义</th>
</tr>
</thead>
<tbody><tr>
<td align="left">-Xms，等价于-XX:InitialHeapSize</td>
<td align="left">设置堆的初始内存大小，默认为物理内存的1/64</td>
</tr>
<tr>
<td align="left">-Xmx，等价于-XX:MaxHeapSize</td>
<td align="left">设置堆的最大内存大小，默认为物理内存的1/4</td>
</tr>
<tr>
<td align="left">-XX:Newratio</td>
<td align="left">设置新生区和养老区的比例，比如值为2（默认值），则养老区是新生区的2倍，即养老区占据堆内存的2/3</td>
</tr>
<tr>
<td align="left">-XX:Surviorratio</td>
<td align="left">设置伊甸园区和一个幸存区的比例，比如值为8（默认值）则表示伊甸园区占新生区的8/10（两个幸存区是一样大的，8:1:1）； 如果设置为5，则比例为5:1:1，即伊甸园区占新生区5/7</td>
</tr>
<tr>
<td align="left">-Xmn</td>
<td align="left">设置堆新生区的内存大小（一般不使用）</td>
</tr>
<tr>
<td align="left">-XX:MaxTenuringThreshold</td>
<td align="left">设置转入养老区的存活次数，默认值为15</td>
</tr>
<tr>
<td align="left">-XX:+PrintFlagsInitial</td>
<td align="left">查看所有参数的默认初始值</td>
</tr>
<tr>
<td align="left">-XX:+PrintFlagsFinal</td>
<td align="left">查看所有参数的最终值（被我们修改后的值不再是默认初始值）</td>
</tr>
</tbody></table>
<p>剩下所有可用参数可以查看oracle官方文档：<a target="_blank" rel="noopener" href="https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html%E3%80%82">https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html。</a></p>
<p><strong>生产环境中，推荐将-Xms和-Xmx设置为一样大，因为这样做的话在Java垃圾回收清理完堆区后不需要重新计算堆区大小，从而提高性能</strong>。此外，要在程序中输出详细的GC处理日志，可以使用<code>-XX:+PrintGCDetails</code>。</p>
<p>比如，我的电脑内存为32GB，所以堆的默认初始值大小为500MB左右，堆的最大值大约为8000MB左右：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">long</span> maxMemory <span class="token operator">=</span> Runtime<span class="token punctuation">.</span><span class="token function">getRuntime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">maxMemory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">long</span> totalMemory <span class="token operator">=</span> Runtime<span class="token punctuation">.</span><span class="token function">getRuntime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">totalMemory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"堆内存的初始值"</span> <span class="token operator">+</span> totalMemory <span class="token operator">/</span> <span class="token number">1024</span> <span class="token operator">/</span> <span class="token number">1024</span> <span class="token operator">+</span> <span class="token string">"mb"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"堆内存的最大值"</span> <span class="token operator">+</span> maxMemory <span class="token operator">/</span> <span class="token number">1024</span> <span class="token operator">/</span> <span class="token number">1024</span> <span class="token operator">+</span> <span class="token string">"mb"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>程序输出：</p>
<pre class=" language-java"><code class="language-java">堆内存的初始值491mb
堆内存的最大值7282mb
</code></pre>
<p>可以通过IDEA调整堆的大小：</p>
<p><img src="https://mrbird.cc/img/QQ20200305-142031@2x.png" alt="QQ20200305-142031@2x"></p>
<p>我们将堆内存的初始大小和最大值都设置为10mb，并且开启GC日志打印，重新运行下面这段程序：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">long</span> maxMemory <span class="token operator">=</span> Runtime<span class="token punctuation">.</span><span class="token function">getRuntime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">maxMemory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">long</span> totalMemory <span class="token operator">=</span> Runtime<span class="token punctuation">.</span><span class="token function">getRuntime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">totalMemory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"堆内存的初始值"</span> <span class="token operator">+</span> totalMemory <span class="token operator">/</span> <span class="token number">1024</span>  <span class="token operator">+</span> <span class="token string">"kb"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"堆内存的最大值"</span> <span class="token operator">+</span> maxMemory <span class="token operator">/</span> <span class="token number">1024</span>  <span class="token operator">+</span> <span class="token string">"kb"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>输出如下所示：</p>
<pre class=" language-java"><code class="language-java">堆内存的初始值9728kb
堆内存的最大值9728kb
Heap
 PSYoungGen      total 2560K<span class="token punctuation">,</span> used 1388K <span class="token punctuation">[</span><span class="token number">0x00000007bfd00000</span><span class="token punctuation">,</span> <span class="token number">0x00000007c0000000</span><span class="token punctuation">,</span> <span class="token number">0x00000007c0000000</span><span class="token punctuation">)</span>
  eden space 2048K<span class="token punctuation">,</span> <span class="token number">67</span><span class="token operator">%</span> used <span class="token punctuation">[</span><span class="token number">0x00000007bfd00000</span><span class="token punctuation">,</span><span class="token number">0x00000007bfe5b370</span><span class="token punctuation">,</span><span class="token number">0x00000007bff00000</span><span class="token punctuation">)</span>
  from space 512K<span class="token punctuation">,</span> <span class="token number">0</span><span class="token operator">%</span> used <span class="token punctuation">[</span><span class="token number">0x00000007bff80000</span><span class="token punctuation">,</span><span class="token number">0x00000007bff80000</span><span class="token punctuation">,</span><span class="token number">0x00000007c0000000</span><span class="token punctuation">)</span>
  to   space 512K<span class="token punctuation">,</span> <span class="token number">0</span><span class="token operator">%</span> used <span class="token punctuation">[</span><span class="token number">0x00000007bff00000</span><span class="token punctuation">,</span><span class="token number">0x00000007bff00000</span><span class="token punctuation">,</span><span class="token number">0x00000007bff80000</span><span class="token punctuation">)</span>
 ParOldGen       total 7168K<span class="token punctuation">,</span> used 0K <span class="token punctuation">[</span><span class="token number">0x00000007bf600000</span><span class="token punctuation">,</span> <span class="token number">0x00000007bfd00000</span><span class="token punctuation">,</span> <span class="token number">0x00000007bfd00000</span><span class="token punctuation">)</span>
  object space 7168K<span class="token punctuation">,</span> <span class="token number">0</span><span class="token operator">%</span> used <span class="token punctuation">[</span><span class="token number">0x00000007bf600000</span><span class="token punctuation">,</span><span class="token number">0x00000007bf600000</span><span class="token punctuation">,</span><span class="token number">0x00000007bfd00000</span><span class="token punctuation">)</span>
 Metaspace       used 2947K<span class="token punctuation">,</span> capacity 4496K<span class="token punctuation">,</span> committed 4864K<span class="token punctuation">,</span> reserved 1056768K
  <span class="token keyword">class</span> <span class="token class-name">space</span>    used 320K<span class="token punctuation">,</span> capacity 388K<span class="token punctuation">,</span> committed 512K<span class="token punctuation">,</span> reserved 1048576K
</code></pre>
<p>可以看到，PSYoungGen（新生区）的总内存大小为2560k，ParOldGen（养老区）的总内存大小为7168k，总和刚好是9728K，这也说明了：Java8后的堆物理上只分为新生区和养老区，Metaspace（元空间）不占用堆内存，而是直接使用物理内存。</p>
<p>那为什么我们设置的堆内存大小是10m（10240kb），控制台输出却只有9728kb呢？从上面的例子我们知道，幸存者区分为0区和1区，根据复制算法的特点，这两个区同一时刻总有一个区是空的，所以控制台输出的内存计算方式为：<strong>2048K(eden space)+512K(from space or to space)+7168K(ParOldGen)=9728K</strong>。9728K再加一个幸存区的大小512K刚好是10240K。</p>
<p>再举个OOM的例子，使用刚刚<code>-Xms10m -Xmx10m -XX:+PrintGCDetails</code>的设置，运行下面这段程序：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        String value <span class="token operator">=</span> <span class="token string">"hello"</span><span class="token punctuation">;</span>
        <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            value <span class="token operator">+=</span> value <span class="token operator">+</span> <span class="token keyword">new</span> <span class="token class-name">Random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">nextInt</span><span class="token punctuation">(</span><span class="token number">1000000000</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token keyword">new</span> <span class="token class-name">Random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">nextInt</span><span class="token punctuation">(</span><span class="token number">1000000000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>输出如下：</p>
<pre class=" language-java"><code class="language-java"><span class="token punctuation">[</span><span class="token function">GC</span> <span class="token punctuation">(</span>Allocation Failure<span class="token punctuation">)</span> <span class="token punctuation">[</span>PSYoungGen<span class="token operator">:</span> 1893K<span class="token operator">-</span><span class="token operator">></span><span class="token function">491K</span><span class="token punctuation">(</span>2560K<span class="token punctuation">)</span><span class="token punctuation">]</span> 1893K<span class="token operator">-</span><span class="token operator">></span><span class="token function">597K</span><span class="token punctuation">(</span>9728K<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.0007246</span> secs<span class="token punctuation">]</span> <span class="token punctuation">[</span>Times<span class="token operator">:</span> user<span class="token operator">=</span><span class="token number">0.01</span> sys<span class="token operator">=</span><span class="token number">0.00</span><span class="token punctuation">,</span> real<span class="token operator">=</span><span class="token number">0.00</span> secs<span class="token punctuation">]</span> 
<span class="token punctuation">[</span><span class="token function">GC</span> <span class="token punctuation">(</span>Allocation Failure<span class="token punctuation">)</span> <span class="token punctuation">[</span>PSYoungGen<span class="token operator">:</span> 2207K<span class="token operator">-</span><span class="token operator">></span><span class="token function">496K</span><span class="token punctuation">(</span>2560K<span class="token punctuation">)</span><span class="token punctuation">]</span> 2313K<span class="token operator">-</span><span class="token operator">></span><span class="token function">1153K</span><span class="token punctuation">(</span>9728K<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.0008383</span> secs<span class="token punctuation">]</span> <span class="token punctuation">[</span>Times<span class="token operator">:</span> user<span class="token operator">=</span><span class="token number">0.00</span> sys<span class="token operator">=</span><span class="token number">0.00</span><span class="token punctuation">,</span> real<span class="token operator">=</span><span class="token number">0.00</span> secs<span class="token punctuation">]</span> 
<span class="token punctuation">[</span><span class="token function">GC</span> <span class="token punctuation">(</span>Allocation Failure<span class="token punctuation">)</span> <span class="token punctuation">[</span>PSYoungGen<span class="token operator">:</span> 2007K<span class="token operator">-</span><span class="token operator">></span><span class="token function">496K</span><span class="token punctuation">(</span>2560K<span class="token punctuation">)</span><span class="token punctuation">]</span> 2664K<span class="token operator">-</span><span class="token operator">></span><span class="token function">1897K</span><span class="token punctuation">(</span>9728K<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.0009456</span> secs<span class="token punctuation">]</span> <span class="token punctuation">[</span>Times<span class="token operator">:</span> user<span class="token operator">=</span><span class="token number">0.01</span> sys<span class="token operator">=</span><span class="token number">0.00</span><span class="token punctuation">,</span> real<span class="token operator">=</span><span class="token number">0.01</span> secs<span class="token punctuation">]</span> 
<span class="token punctuation">[</span><span class="token function">GC</span> <span class="token punctuation">(</span>Allocation Failure<span class="token punctuation">)</span> <span class="token punctuation">[</span>PSYoungGen<span class="token operator">:</span> 2021K<span class="token operator">-</span><span class="token operator">></span><span class="token function">496K</span><span class="token punctuation">(</span>2560K<span class="token punctuation">)</span><span class="token punctuation">]</span> 4894K<span class="token operator">-</span><span class="token operator">></span><span class="token function">4113K</span><span class="token punctuation">(</span>9728K<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.0010814</span> secs<span class="token punctuation">]</span> <span class="token punctuation">[</span>Times<span class="token operator">:</span> user<span class="token operator">=</span><span class="token number">0.00</span> sys<span class="token operator">=</span><span class="token number">0.00</span><span class="token punctuation">,</span> real<span class="token operator">=</span><span class="token number">0.00</span> secs<span class="token punctuation">]</span> 
<span class="token punctuation">[</span><span class="token function">GC</span> <span class="token punctuation">(</span>Allocation Failure<span class="token punctuation">)</span> <span class="token punctuation">[</span>PSYoungGen<span class="token operator">:</span> 1359K<span class="token operator">-</span><span class="token operator">></span><span class="token function">496K</span><span class="token punctuation">(</span>2560K<span class="token punctuation">)</span><span class="token punctuation">]</span> 6448K<span class="token operator">-</span><span class="token operator">></span><span class="token function">5600K</span><span class="token punctuation">(</span>9728K<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.0015792</span> secs<span class="token punctuation">]</span> <span class="token punctuation">[</span>Times<span class="token operator">:</span> user<span class="token operator">=</span><span class="token number">0.00</span> sys<span class="token operator">=</span><span class="token number">0.00</span><span class="token punctuation">,</span> real<span class="token operator">=</span><span class="token number">0.00</span> secs<span class="token punctuation">]</span> 
<span class="token punctuation">[</span><span class="token function">GC</span> <span class="token punctuation">(</span>Allocation Failure<span class="token punctuation">)</span> <span class="token punctuation">[</span>PSYoungGen<span class="token operator">:</span> 496K<span class="token operator">-</span><span class="token operator">></span><span class="token function">496K</span><span class="token punctuation">(</span>1536K<span class="token punctuation">)</span><span class="token punctuation">]</span> 5600K<span class="token operator">-</span><span class="token operator">></span><span class="token function">5600K</span><span class="token punctuation">(</span>8704K<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.0006416</span> secs<span class="token punctuation">]</span> <span class="token punctuation">[</span>Times<span class="token operator">:</span> user<span class="token operator">=</span><span class="token number">0.01</span> sys<span class="token operator">=</span><span class="token number">0.00</span><span class="token punctuation">,</span> real<span class="token operator">=</span><span class="token number">0.00</span> secs<span class="token punctuation">]</span> 
<span class="token punctuation">[</span>Full <span class="token function">GC</span> <span class="token punctuation">(</span>Allocation Failure<span class="token punctuation">)</span> <span class="token punctuation">[</span>PSYoungGen<span class="token operator">:</span> 496K<span class="token operator">-</span><span class="token operator">></span><span class="token function">0K</span><span class="token punctuation">(</span>1536K<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>ParOldGen<span class="token operator">:</span> 5104K<span class="token operator">-</span><span class="token operator">></span><span class="token function">2585K</span><span class="token punctuation">(</span>7168K<span class="token punctuation">)</span><span class="token punctuation">]</span> 5600K<span class="token operator">-</span><span class="token operator">></span><span class="token function">2585K</span><span class="token punctuation">(</span>8704K<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>Metaspace<span class="token operator">:</span> 2982K<span class="token operator">-</span><span class="token operator">></span><span class="token function">2982K</span><span class="token punctuation">(</span>1056768K<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">0.0044783</span> secs<span class="token punctuation">]</span> <span class="token punctuation">[</span>Times<span class="token operator">:</span> user<span class="token operator">=</span><span class="token number">0.02</span> sys<span class="token operator">=</span><span class="token number">0.00</span><span class="token punctuation">,</span> real<span class="token operator">=</span><span class="token number">0.01</span> secs<span class="token punctuation">]</span> 
<span class="token punctuation">[</span><span class="token function">GC</span> <span class="token punctuation">(</span>Allocation Failure<span class="token punctuation">)</span> <span class="token punctuation">[</span>PSYoungGen<span class="token operator">:</span> 61K<span class="token operator">-</span><span class="token operator">></span><span class="token function">192K</span><span class="token punctuation">(</span>2048K<span class="token punctuation">)</span><span class="token punctuation">]</span> 7061K<span class="token operator">-</span><span class="token operator">></span><span class="token function">7192K</span><span class="token punctuation">(</span>9216K<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.0012566</span> secs<span class="token punctuation">]</span> <span class="token punctuation">[</span>Times<span class="token operator">:</span> user<span class="token operator">=</span><span class="token number">0.01</span> sys<span class="token operator">=</span><span class="token number">0.00</span><span class="token punctuation">,</span> real<span class="token operator">=</span><span class="token number">0.00</span> secs<span class="token punctuation">]</span> 
<span class="token punctuation">[</span>Full <span class="token function">GC</span> <span class="token punctuation">(</span>Ergonomics<span class="token punctuation">)</span> <span class="token punctuation">[</span>PSYoungGen<span class="token operator">:</span> 192K<span class="token operator">-</span><span class="token operator">></span><span class="token function">0K</span><span class="token punctuation">(</span>2048K<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>ParOldGen<span class="token operator">:</span> 7000K<span class="token operator">-</span><span class="token operator">></span><span class="token function">1840K</span><span class="token punctuation">(</span>7168K<span class="token punctuation">)</span><span class="token punctuation">]</span> 7192K<span class="token operator">-</span><span class="token operator">></span><span class="token function">1840K</span><span class="token punctuation">(</span>9216K<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>Metaspace<span class="token operator">:</span> 3042K<span class="token operator">-</span><span class="token operator">></span><span class="token function">3042K</span><span class="token punctuation">(</span>1056768K<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">0.0072023</span> secs<span class="token punctuation">]</span> <span class="token punctuation">[</span>Times<span class="token operator">:</span> user<span class="token operator">=</span><span class="token number">0.02</span> sys<span class="token operator">=</span><span class="token number">0.00</span><span class="token punctuation">,</span> real<span class="token operator">=</span><span class="token number">0.01</span> secs<span class="token punctuation">]</span> 
<span class="token punctuation">[</span><span class="token function">GC</span> <span class="token punctuation">(</span>Allocation Failure<span class="token punctuation">)</span> <span class="token punctuation">[</span>PSYoungGen<span class="token operator">:</span> 65K<span class="token operator">-</span><span class="token operator">></span><span class="token function">160K</span><span class="token punctuation">(</span>2048K<span class="token punctuation">)</span><span class="token punctuation">]</span> 6321K<span class="token operator">-</span><span class="token operator">></span><span class="token function">6416K</span><span class="token punctuation">(</span>9216K<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.0022603</span> secs<span class="token punctuation">]</span> <span class="token punctuation">[</span>Times<span class="token operator">:</span> user<span class="token operator">=</span><span class="token number">0.02</span> sys<span class="token operator">=</span><span class="token number">0.00</span><span class="token punctuation">,</span> real<span class="token operator">=</span><span class="token number">0.00</span> secs<span class="token punctuation">]</span> 
<span class="token punctuation">[</span>Full <span class="token function">GC</span> <span class="token punctuation">(</span>Ergonomics<span class="token punctuation">)</span> <span class="token punctuation">[</span>PSYoungGen<span class="token operator">:</span> 160K<span class="token operator">-</span><span class="token operator">></span><span class="token function">0K</span><span class="token punctuation">(</span>2048K<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>ParOldGen<span class="token operator">:</span> 6256K<span class="token operator">-</span><span class="token operator">></span><span class="token function">4785K</span><span class="token punctuation">(</span>7168K<span class="token punctuation">)</span><span class="token punctuation">]</span> 6416K<span class="token operator">-</span><span class="token operator">></span><span class="token function">4785K</span><span class="token punctuation">(</span>9216K<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>Metaspace<span class="token operator">:</span> 3076K<span class="token operator">-</span><span class="token operator">></span><span class="token function">3076K</span><span class="token punctuation">(</span>1056768K<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">0.0056740</span> secs<span class="token punctuation">]</span> <span class="token punctuation">[</span>Times<span class="token operator">:</span> user<span class="token operator">=</span><span class="token number">0.03</span> sys<span class="token operator">=</span><span class="token number">0.00</span><span class="token punctuation">,</span> real<span class="token operator">=</span><span class="token number">0.01</span> secs<span class="token punctuation">]</span> 
<span class="token punctuation">[</span><span class="token function">GC</span> <span class="token punctuation">(</span>Allocation Failure<span class="token punctuation">)</span> <span class="token punctuation">[</span>PSYoungGen<span class="token operator">:</span> 0K<span class="token operator">-</span><span class="token operator">></span><span class="token function">0K</span><span class="token punctuation">(</span>2048K<span class="token punctuation">)</span><span class="token punctuation">]</span> 4785K<span class="token operator">-</span><span class="token operator">></span><span class="token function">4785K</span><span class="token punctuation">(</span>9216K<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.0003871</span> secs<span class="token punctuation">]</span> <span class="token punctuation">[</span>Times<span class="token operator">:</span> user<span class="token operator">=</span><span class="token number">0.00</span> sys<span class="token operator">=</span><span class="token number">0.00</span><span class="token punctuation">,</span> real<span class="token operator">=</span><span class="token number">0.00</span> secs<span class="token punctuation">]</span> 
<span class="token punctuation">[</span>Full <span class="token function">GC</span> <span class="token punctuation">(</span>Allocation Failure<span class="token punctuation">)</span> <span class="token punctuation">[</span>PSYoungGen<span class="token operator">:</span> 0K<span class="token operator">-</span><span class="token operator">></span><span class="token function">0K</span><span class="token punctuation">(</span>2048K<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>ParOldGen<span class="token operator">:</span> 4785K<span class="token operator">-</span><span class="token operator">></span><span class="token function">4765K</span><span class="token punctuation">(</span>7168K<span class="token punctuation">)</span><span class="token punctuation">]</span> 4785K<span class="token operator">-</span><span class="token operator">></span><span class="token function">4765K</span><span class="token punctuation">(</span>9216K<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>Metaspace<span class="token operator">:</span> 3076K<span class="token operator">-</span><span class="token operator">></span><span class="token function">3076K</span><span class="token punctuation">(</span>1056768K<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">0.0049903</span> secs<span class="token punctuation">]</span> <span class="token punctuation">[</span>Times<span class="token operator">:</span> user<span class="token operator">=</span><span class="token number">0.02</span> sys<span class="token operator">=</span><span class="token number">0.00</span><span class="token punctuation">,</span> real<span class="token operator">=</span><span class="token number">0.00</span> secs<span class="token punctuation">]</span> 
Heap
 PSYoungGen      total 2048K<span class="token punctuation">,</span> used 59K <span class="token punctuation">[</span><span class="token number">0x00000007bfd00000</span><span class="token punctuation">,</span> <span class="token number">0x00000007c0000000</span><span class="token punctuation">,</span> <span class="token number">0x00000007c0000000</span><span class="token punctuation">)</span>
  eden space 1024K<span class="token punctuation">,</span> <span class="token number">5</span><span class="token operator">%</span> used <span class="token punctuation">[</span><span class="token number">0x00000007bfd00000</span><span class="token punctuation">,</span><span class="token number">0x00000007bfd0efb8</span><span class="token punctuation">,</span><span class="token number">0x00000007bfe00000</span><span class="token punctuation">)</span>
  from space 1024K<span class="token punctuation">,</span> <span class="token number">0</span><span class="token operator">%</span> used <span class="token punctuation">[</span><span class="token number">0x00000007bfe00000</span><span class="token punctuation">,</span><span class="token number">0x00000007bfe00000</span><span class="token punctuation">,</span><span class="token number">0x00000007bff00000</span><span class="token punctuation">)</span>
  to   space 1024K<span class="token punctuation">,</span> <span class="token number">0</span><span class="token operator">%</span> used <span class="token punctuation">[</span><span class="token number">0x00000007bff00000</span><span class="token punctuation">,</span><span class="token number">0x00000007bff00000</span><span class="token punctuation">,</span><span class="token number">0x00000007c0000000</span><span class="token punctuation">)</span>
 ParOldGen       total 7168K<span class="token punctuation">,</span> used 4765K <span class="token punctuation">[</span><span class="token number">0x00000007bf600000</span><span class="token punctuation">,</span> <span class="token number">0x00000007bfd00000</span><span class="token punctuation">,</span> <span class="token number">0x00000007bfd00000</span><span class="token punctuation">)</span>
  object space 7168K<span class="token punctuation">,</span> <span class="token number">66</span><span class="token operator">%</span> used <span class="token punctuation">[</span><span class="token number">0x00000007bf600000</span><span class="token punctuation">,</span><span class="token number">0x00000007bfaa77b8</span><span class="token punctuation">,</span><span class="token number">0x00000007bfd00000</span><span class="token punctuation">)</span>
 Metaspace       used 3113K<span class="token punctuation">,</span> capacity 4496K<span class="token punctuation">,</span> committed 4864K<span class="token punctuation">,</span> reserved 1056768K
  <span class="token keyword">class</span> <span class="token class-name">space</span>    used 339K<span class="token punctuation">,</span> capacity 388K<span class="token punctuation">,</span> committed 512K<span class="token punctuation">,</span> reserved 1048576K
Exception in thread <span class="token string">"main"</span> java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>OutOfMemoryError<span class="token operator">:</span> Java heap space
    at java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>Arrays<span class="token punctuation">.</span><span class="token function">copyOf</span><span class="token punctuation">(</span>Arrays<span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">3332</span><span class="token punctuation">)</span>
    at java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>AbstractStringBuilder<span class="token punctuation">.</span><span class="token function">ensureCapacityInternal</span><span class="token punctuation">(</span>AbstractStringBuilder<span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">124</span><span class="token punctuation">)</span>
    at java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>AbstractStringBuilder<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>AbstractStringBuilder<span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">674</span><span class="token punctuation">)</span>
    at java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>StringBuilder<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>StringBuilder<span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">208</span><span class="token punctuation">)</span>
    at cc<span class="token punctuation">.</span>mrbird<span class="token punctuation">.</span>Test<span class="token punctuation">.</span><span class="token function">main</span><span class="token punctuation">(</span>Test<span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">19</span><span class="token punctuation">)</span>
</code></pre>
<p>可以看到，经过数次的GC和Full GC后，堆内存还是无法腾出空间，最终抛出OOM错误。日志的含义如下图所示：</p>
<p>Young GC（Minor GC）：</p>
<p><img src="https://mrbird.cc/img/QQ20200305-145255@2x.png" alt="QQ20200305-145255@2x"></p>
<p>Full GC（Major GC）：</p>
<p><img src="https://mrbird.cc/img/QQ20200305-171134@2x.png" alt="QQ20200305-171134@2x"></p>
<h3 id="TLAB"><a href="#TLAB" class="headerlink" title="TLAB"></a>TLAB</h3><p>JVM对伊甸园区继续进行划分，为每个线程分配了一个私有缓存区域，这块区域就是TLAB（Thread Local Allocation Buffer）。多线程同时分配内存时，使用TLAB可以避免一系列非线程安全问题，同时还能够提升内存分配的吞吐量。尽管不是所有的对象实例都能够在TLAB中成功分配内存，但JVM确实是将TLAB作为内存分配的首选：</p>
<p><img src="https://mrbird.cc/img/QQ20200629-142307@2x.png" alt="QQ20200629-142307@2x"></p>
<p><img src="https://mrbird.cc/img/QQ20200630-112921@2x.png" alt="QQ20200630-112921@2x"></p>
<p>我们可以使用<code>-XX:UseTLAB</code>设置是否开启TLAB，举个例子：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> InterruptedException <span class="token punctuation">{</span>
        TimeUnit<span class="token punctuation">.</span>SECONDS<span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre>
<p>运行main方法：</p>
<p><img src="https://mrbird.cc/img/QQ20200629-141728@2x.png" alt="QQ20200629-141728@2x"></p>
<p>可以看到TLAB默认是开启的。</p>
<p>TLAB空间的内存非常小，仅占整个伊甸园区的1%，可以通过<code>-XX:TLABWasteTargetPercent</code>设置TLAB空间所占用伊甸园区空间的百分比。</p>
<p>有了TLAB的概念后，我们就不能说堆空间一定是线程共享的了。</p>
<h2 id="方法区"><a href="#方法区" class="headerlink" title="方法区"></a>方法区</h2><p><strong>方法区</strong>并不是所谓的<del>存储方法的区域</del>，而是供各线程共享的运行时内存区域。它存储了已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等。</p>
<p>方法区也是<strong>一种规范</strong>，在不同虚拟机里头实现是不一样的，最典型的实现就是HotSpot虚拟机Java8之前的永久代(PermGen space)和Java8的元空间(Metaspace)。</p>
<h3 id="设置方法区大小"><a href="#设置方法区大小" class="headerlink" title="设置方法区大小"></a>设置方法区大小</h3><p>方法区的大小决定了系统可以加载多少个类，如果系统定义了太多的类，导致方法区溢出，虚拟机则会抛出java.lang.OutOfMemoryError: PermGen space（Java 7）或者java.lang.OutOfMemoryError: Metaspace（Java 8）内存溢出错误。</p>
<p>以Java8版本为例，我们可以使用<code>-XX:MetaspaceSize=size</code>设置元空间初始大小，<code>-XX:MaxMetaspaceSize=size</code>设置元空间最大值。默认情况下，在windows平台上，<code>-XX:MetaspaceSize</code>值为21M，<code>-XX:MaxMetaspaceSize</code>值为-1，即没有限制，所以极端情况下如果不断地加载类，虚拟机会耗尽所有可用的系统内存。</p>
<p>下面举个元空间OOM的例子：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">import</span> com<span class="token punctuation">.</span>sun<span class="token punctuation">.</span>org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>bcel<span class="token punctuation">.</span>internal<span class="token punctuation">.</span>util<span class="token punctuation">.</span>ClassLoader<span class="token punctuation">;</span>
<span class="token keyword">import</span> com<span class="token punctuation">.</span>sun<span class="token punctuation">.</span>xml<span class="token punctuation">.</span>internal<span class="token punctuation">.</span>ws<span class="token punctuation">.</span>org<span class="token punctuation">.</span>objectweb<span class="token punctuation">.</span>asm<span class="token punctuation">.</span>ClassWriter<span class="token punctuation">;</span>
<span class="token keyword">import</span> jdk<span class="token punctuation">.</span>internal<span class="token punctuation">.</span>org<span class="token punctuation">.</span>objectweb<span class="token punctuation">.</span>asm<span class="token punctuation">.</span>Opcodes<span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token keyword">extends</span> <span class="token class-name">ClassLoader</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> count <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            Test test <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Test</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">10000</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                String className <span class="token operator">=</span> <span class="token string">"Class"</span> <span class="token operator">+</span> i<span class="token punctuation">;</span>
                <span class="token comment" spellcheck="true">// 创建ClassWriter对象，用于生成类的二进制字节码</span>
                ClassWriter classWriter <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ClassWriter</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment" spellcheck="true">// 指定版本号、修饰符、类名、包名、父类和接口</span>
                classWriter<span class="token punctuation">.</span><span class="token function">visit</span><span class="token punctuation">(</span>Opcodes<span class="token punctuation">.</span>V1_8<span class="token punctuation">,</span> Opcodes<span class="token punctuation">.</span>ACC_PUBLIC<span class="token punctuation">,</span> className<span class="token punctuation">,</span> null<span class="token punctuation">,</span> <span class="token string">"java/lang/Object"</span><span class="token punctuation">,</span> null<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> bytes <span class="token operator">=</span> classWriter<span class="token punctuation">.</span><span class="token function">toByteArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment" spellcheck="true">// 加载类</span>
                test<span class="token punctuation">.</span><span class="token function">defineClass</span><span class="token punctuation">(</span>className<span class="token punctuation">,</span> bytes<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> bytes<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span>
                count<span class="token operator">++</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
            System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>count<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>上面例子中，我们尝试加载10000个类，通过参数<code>-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m</code>将元空间大小设置为固定大小10M，运行上面的程序控制台输出：</p>
<p><img src="https://mrbird.cc/img/QQ20200630-110519@2x.png" alt="QQ20200630-110519@2x"></p>
<h3 id="方法区、堆、栈关系"><a href="#方法区、堆、栈关系" class="headerlink" title="方法区、堆、栈关系"></a>方法区、堆、栈关系</h3><p>方法区和堆、栈的关系如下图所示：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Bird</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        Bird bird <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Bird</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p><img src="https://mrbird.cc/img/QQ20200630-113730@2x.png" alt="QQ20200630-113730@2x"></p>
<p><img src="https://mrbird.cc/img/QQ20200630-135333@2x.png" alt="QQ20200630-135333@2x"></p>
<h3 id="方法区内部结构"><a href="#方法区内部结构" class="headerlink" title="方法区内部结构"></a>方法区内部结构</h3><p>方法区内部主要存储了以下内容（不同JDK版本内容有所不同，具体参考下面“方法区演进”）：</p>
<h4 id="类型信息"><a href="#类型信息" class="headerlink" title="类型信息"></a>类型信息</h4><p>对每个加载的类型（类class、接口 interface、枚举enum、注解 annotation），JVM必须在方法区中存储以下类型信息：</p>
<ol>
<li>这个类型的完整有效名称（包名.类名）；</li>
<li>这个类型直接父类的完整有效名（interface和java.lang.Object没有父类）；</li>
<li>这个类的修饰符（public，abstract，final）；</li>
<li>这个类型直接接口的一个有序列表（一个类可以实现多个接口）。</li>
</ol>
<h4 id="方法信息"><a href="#方法信息" class="headerlink" title="方法信息"></a>方法信息</h4><p>方法信息包含了这个类的所有方法信息（包括构造器），这些信息和其声明顺序一致：</p>
<ol>
<li>方法名称；</li>
<li>方法的返回值类型（没有返回值则是void）；</li>
<li>方法参数的数量和类型（有序）；</li>
<li>方法的修饰符（public，private，protected，static，final，synchronized，native，abstract）；</li>
<li>方法的字节码、操作数栈、局部变量表及其大小（abstract和native方法除外）；</li>
<li>异常表（abstract和native方法除外）。</li>
</ol>
<h4 id="域信息"><a href="#域信息" class="headerlink" title="域信息"></a>域信息</h4><p>域Field我们也常称为属性，字段。域信息包含：</p>
<ol>
<li>域的声明顺序；</li>
<li>域的相关信息，包括名称、类型、修饰符（public，private，protected，static，final，volatile，transient）。</li>
</ol>
<h4 id="JIT代码缓存"><a href="#JIT代码缓存" class="headerlink" title="JIT代码缓存"></a>JIT代码缓存</h4><p>这部分在👇执行引擎中再做说明。</p>
<h4 id="运行时常量池"><a href="#运行时常量池" class="headerlink" title="运行时常量池"></a>运行时常量池</h4><p>在上面虚拟机栈的介绍中，我们知道类字节码反编译后，会有一个constant pool的结构，俗称为常量池，所有的变量和方法引用都作为符号引用保存在class文件的常量池里。虚拟机栈的动态链接就是将符号引用（这些符号引用的集合就是常量池）转换为直接引用（符号引用对应的具体信息，这些具体信息的集合就是运行时常量池，存在方法区中）的过程。</p>
<h4 id="静态变量"><a href="#静态变量" class="headerlink" title="静态变量"></a>静态变量</h4><p>静态变量就是使用static修饰的域信息。静态变量和类关联在一起，随着类的加载而加载，它们成为类数据在逻辑上的一部分。静态变量也成为类变量，类变量被类的所有实例共享，即使没有类实例时你也可以访问它：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> String hello <span class="token operator">=</span> <span class="token string">"hello"</span><span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"hello"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        Test test <span class="token operator">=</span> null<span class="token punctuation">;</span>
        test<span class="token punctuation">.</span><span class="token function">hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>test<span class="token punctuation">.</span>hello<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>上面程序运行并不会报空指针异常。</p>
<p>通过final修饰的静态变量我们俗称常量。常量在编译的时候就会被分配具体值：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> String hello <span class="token operator">=</span> <span class="token string">"hello"</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> String HELLO <span class="token operator">=</span> <span class="token string">"hello"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>通过<code>javap -v -p Test.class</code>查看其字节码：</p>
<p><img src="https://mrbird.cc/img/QQ20200630-170711@2x.png" alt="QQ20200630-170711@2x"></p>
<p>通过上面的学习我们知道，静态变量（类变量）在类加载过程的初始化阶段才会被赋值。</p>
<h4 id="演示方法区内部结构"><a href="#演示方法区内部结构" class="headerlink" title="演示方法区内部结构"></a>演示方法区内部结构</h4><p>下面通过字节码内容来查看上面这些信息，现有如下代码：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token keyword">extends</span> <span class="token class-name">Object</span> <span class="token keyword">implements</span> <span class="token class-name">Cloneable</span><span class="token punctuation">,</span> Serializable <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> String hello <span class="token operator">=</span> <span class="token string">"hello"</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> String HELLO <span class="token operator">=</span> <span class="token string">"hello"</span><span class="token punctuation">;</span>
    <span class="token keyword">public</span> <span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">method1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"method1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> String <span class="token function">method2</span><span class="token punctuation">(</span>String name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
            <span class="token keyword">int</span> b <span class="token operator">=</span> a <span class="token operator">/</span> <span class="token number">0</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> name<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>通过<code>javap -v -p Test.class</code>查看其字节码：</p>
<pre class=" language-java"><code class="language-java">Classfile <span class="token operator">/</span>Users<span class="token operator">/</span>mrbird<span class="token operator">/</span>idea workspace<span class="token operator">/</span>JVM<span class="token operator">-</span>Learn<span class="token operator">/</span>target<span class="token operator">/</span>classes<span class="token operator">/</span>cc<span class="token operator">/</span>mrbird<span class="token operator">/</span>jvm<span class="token operator">/</span>learn<span class="token operator">/</span>Test<span class="token punctuation">.</span><span class="token keyword">class</span>
  <span class="token class-name">Last</span> modified <span class="token number">2019</span><span class="token operator">-</span><span class="token number">4</span><span class="token operator">-</span><span class="token number">01</span><span class="token punctuation">;</span> size <span class="token number">1016</span> bytes
  MD5 checksum ab0309674b0f0b5fbd0766af035efe0a
  Compiled from <span class="token string">"Test.java"</span>
<span class="token comment" spellcheck="true">// 类型信息</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">cc<span class="token punctuation">.</span>mrbird<span class="token punctuation">.</span>jvm<span class="token punctuation">.</span>learn<span class="token punctuation">.</span>Test</span> <span class="token keyword">implements</span> <span class="token class-name">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>Cloneable</span><span class="token punctuation">,</span>java<span class="token punctuation">.</span>io<span class="token punctuation">.</span>Serializable
  minor version<span class="token operator">:</span> <span class="token number">0</span>
  major version<span class="token operator">:</span> <span class="token number">52</span>
  <span class="token comment" spellcheck="true">// 类的修饰符</span>
  flags<span class="token operator">:</span> ACC_PUBLIC<span class="token punctuation">,</span> ACC_SUPER
<span class="token comment" spellcheck="true">// 常量池</span>
Constant pool<span class="token operator">:</span>
   #<span class="token number">1</span> <span class="token operator">=</span> Methodref          #<span class="token number">11</span><span class="token punctuation">.</span>#<span class="token number">38</span>        <span class="token comment" spellcheck="true">// java/lang/Object."&lt;init>":()V</span>
   #<span class="token number">2</span> <span class="token operator">=</span> Fieldref           #<span class="token number">10</span><span class="token punctuation">.</span>#<span class="token number">39</span>        <span class="token comment" spellcheck="true">// cc/mrbird/jvm/learn/Test.a:I</span>
   #<span class="token number">3</span> <span class="token operator">=</span> Fieldref           #<span class="token number">40</span><span class="token punctuation">.</span>#<span class="token number">41</span>        <span class="token comment" spellcheck="true">// java/lang/System.out:Ljava/io/PrintStream;</span>
   #<span class="token number">4</span> <span class="token operator">=</span> String             #<span class="token number">27</span>            <span class="token comment" spellcheck="true">// method1</span>
   #<span class="token number">5</span> <span class="token operator">=</span> Methodref          #<span class="token number">42</span><span class="token punctuation">.</span>#<span class="token number">43</span>        <span class="token comment" spellcheck="true">// java/io/PrintStream.println:(Ljava/lang/String;)V</span>
   #<span class="token number">6</span> <span class="token operator">=</span> Class              #<span class="token number">44</span>            <span class="token comment" spellcheck="true">// java/lang/Exception</span>
   #<span class="token number">7</span> <span class="token operator">=</span> Methodref          #<span class="token number">6</span><span class="token punctuation">.</span>#<span class="token number">45</span>         <span class="token comment" spellcheck="true">// java/lang/Exception.printStackTrace:()V</span>
   #<span class="token number">8</span> <span class="token operator">=</span> String             #<span class="token number">14</span>            <span class="token comment" spellcheck="true">// hello</span>
   #<span class="token number">9</span> <span class="token operator">=</span> Fieldref           #<span class="token number">10</span><span class="token punctuation">.</span>#<span class="token number">46</span>        <span class="token comment" spellcheck="true">// cc/mrbird/jvm/learn/Test.hello:Ljava/lang/String;</span>
  #<span class="token number">10</span> <span class="token operator">=</span> Class              #<span class="token number">47</span>            <span class="token comment" spellcheck="true">// cc/mrbird/jvm/learn/Test</span>
  #<span class="token number">11</span> <span class="token operator">=</span> Class              #<span class="token number">48</span>            <span class="token comment" spellcheck="true">// java/lang/Object</span>
  #<span class="token number">12</span> <span class="token operator">=</span> Class              #<span class="token number">49</span>            <span class="token comment" spellcheck="true">// java/lang/Cloneable</span>
  #<span class="token number">13</span> <span class="token operator">=</span> Class              #<span class="token number">50</span>            <span class="token comment" spellcheck="true">// java/io/Serializable</span>
  #<span class="token number">14</span> <span class="token operator">=</span> Utf8               hello
  #<span class="token number">15</span> <span class="token operator">=</span> Utf8               Ljava<span class="token operator">/</span>lang<span class="token operator">/</span>String<span class="token punctuation">;</span>
  #<span class="token number">16</span> <span class="token operator">=</span> Utf8               HELLO
  #<span class="token number">17</span> <span class="token operator">=</span> Utf8               ConstantValue
  #<span class="token number">18</span> <span class="token operator">=</span> Utf8               a
  #<span class="token number">19</span> <span class="token operator">=</span> Utf8               I
  #<span class="token number">20</span> <span class="token operator">=</span> Utf8               <span class="token operator">&lt;</span>init<span class="token operator">></span>
  #<span class="token number">21</span> <span class="token operator">=</span> <span class="token function">Utf8</span>               <span class="token punctuation">(</span><span class="token punctuation">)</span>V
  #<span class="token number">22</span> <span class="token operator">=</span> Utf8               Code
  #<span class="token number">23</span> <span class="token operator">=</span> Utf8               LineNumberTable
  #<span class="token number">24</span> <span class="token operator">=</span> Utf8               LocalVariableTable
  #<span class="token number">25</span> <span class="token operator">=</span> Utf8               <span class="token keyword">this</span>
  #<span class="token number">26</span> <span class="token operator">=</span> Utf8               Lcc<span class="token operator">/</span>mrbird<span class="token operator">/</span>jvm<span class="token operator">/</span>learn<span class="token operator">/</span>Test<span class="token punctuation">;</span>
  #<span class="token number">27</span> <span class="token operator">=</span> Utf8               method1
  #<span class="token number">28</span> <span class="token operator">=</span> Utf8               method2
  #<span class="token number">29</span> <span class="token operator">=</span> <span class="token function">Utf8</span>               <span class="token punctuation">(</span>Ljava<span class="token operator">/</span>lang<span class="token operator">/</span>String<span class="token punctuation">;</span><span class="token punctuation">)</span>Ljava<span class="token operator">/</span>lang<span class="token operator">/</span>String<span class="token punctuation">;</span>
  #<span class="token number">30</span> <span class="token operator">=</span> Utf8               e
  #<span class="token number">31</span> <span class="token operator">=</span> Utf8               Ljava<span class="token operator">/</span>lang<span class="token operator">/</span>Exception<span class="token punctuation">;</span>
  #<span class="token number">32</span> <span class="token operator">=</span> Utf8               name
  #<span class="token number">33</span> <span class="token operator">=</span> Utf8               StackMapTable
  #<span class="token number">34</span> <span class="token operator">=</span> Class              #<span class="token number">44</span>            <span class="token comment" spellcheck="true">// java/lang/Exception</span>
  #<span class="token number">35</span> <span class="token operator">=</span> Utf8               <span class="token operator">&lt;</span>clinit<span class="token operator">></span>
  #<span class="token number">36</span> <span class="token operator">=</span> Utf8               SourceFile
  #<span class="token number">37</span> <span class="token operator">=</span> Utf8               Test<span class="token punctuation">.</span>java
  #<span class="token number">38</span> <span class="token operator">=</span> NameAndType        #<span class="token number">20</span><span class="token operator">:</span>#<span class="token number">21</span>        <span class="token comment" spellcheck="true">// "&lt;init>":()V</span>
  #<span class="token number">39</span> <span class="token operator">=</span> NameAndType        #<span class="token number">18</span><span class="token operator">:</span>#<span class="token number">19</span>        <span class="token comment" spellcheck="true">// a:I</span>
  #<span class="token number">40</span> <span class="token operator">=</span> Class              #<span class="token number">51</span>            <span class="token comment" spellcheck="true">// java/lang/System</span>
  #<span class="token number">41</span> <span class="token operator">=</span> NameAndType        #<span class="token number">52</span><span class="token operator">:</span>#<span class="token number">53</span>        <span class="token comment" spellcheck="true">// out:Ljava/io/PrintStream;</span>
  #<span class="token number">42</span> <span class="token operator">=</span> Class              #<span class="token number">54</span>            <span class="token comment" spellcheck="true">// java/io/PrintStream</span>
  #<span class="token number">43</span> <span class="token operator">=</span> NameAndType        #<span class="token number">55</span><span class="token operator">:</span>#<span class="token number">56</span>        <span class="token comment" spellcheck="true">// println:(Ljava/lang/String;)V</span>
  #<span class="token number">44</span> <span class="token operator">=</span> Utf8               java<span class="token operator">/</span>lang<span class="token operator">/</span>Exception
  #<span class="token number">45</span> <span class="token operator">=</span> NameAndType        #<span class="token number">57</span><span class="token operator">:</span>#<span class="token number">21</span>        <span class="token comment" spellcheck="true">// printStackTrace:()V</span>
  #<span class="token number">46</span> <span class="token operator">=</span> NameAndType        #<span class="token number">14</span><span class="token operator">:</span>#<span class="token number">15</span>        <span class="token comment" spellcheck="true">// hello:Ljava/lang/String;</span>
  #<span class="token number">47</span> <span class="token operator">=</span> Utf8               cc<span class="token operator">/</span>mrbird<span class="token operator">/</span>jvm<span class="token operator">/</span>learn<span class="token operator">/</span>Test
  #<span class="token number">48</span> <span class="token operator">=</span> Utf8               java<span class="token operator">/</span>lang<span class="token operator">/</span>Object
  #<span class="token number">49</span> <span class="token operator">=</span> Utf8               java<span class="token operator">/</span>lang<span class="token operator">/</span>Cloneable
  #<span class="token number">50</span> <span class="token operator">=</span> Utf8               java<span class="token operator">/</span>io<span class="token operator">/</span>Serializable
  #<span class="token number">51</span> <span class="token operator">=</span> Utf8               java<span class="token operator">/</span>lang<span class="token operator">/</span>System
  #<span class="token number">52</span> <span class="token operator">=</span> Utf8               out
  #<span class="token number">53</span> <span class="token operator">=</span> Utf8               Ljava<span class="token operator">/</span>io<span class="token operator">/</span>PrintStream<span class="token punctuation">;</span>
  #<span class="token number">54</span> <span class="token operator">=</span> Utf8               java<span class="token operator">/</span>io<span class="token operator">/</span>PrintStream
  #<span class="token number">55</span> <span class="token operator">=</span> Utf8               println
  #<span class="token number">56</span> <span class="token operator">=</span> <span class="token function">Utf8</span>               <span class="token punctuation">(</span>Ljava<span class="token operator">/</span>lang<span class="token operator">/</span>String<span class="token punctuation">;</span><span class="token punctuation">)</span>V
  #<span class="token number">57</span> <span class="token operator">=</span> Utf8               printStackTrace
<span class="token punctuation">{</span>

  <span class="token comment" spellcheck="true">// 域信息</span>
  <span class="token keyword">private</span> <span class="token keyword">static</span> java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>String hello<span class="token punctuation">;</span>
    descriptor<span class="token operator">:</span> Ljava<span class="token operator">/</span>lang<span class="token operator">/</span>String<span class="token punctuation">;</span>
    flags<span class="token operator">:</span> ACC_PRIVATE<span class="token punctuation">,</span> ACC_STATIC
  <span class="token comment" spellcheck="true">// 域信息</span>
  <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>String HELLO<span class="token punctuation">;</span>
    descriptor<span class="token operator">:</span> Ljava<span class="token operator">/</span>lang<span class="token operator">/</span>String<span class="token punctuation">;</span>
    flags<span class="token operator">:</span> ACC_PRIVATE<span class="token punctuation">,</span> ACC_STATIC<span class="token punctuation">,</span> ACC_FINAL
    ConstantValue<span class="token operator">:</span> String hello
  <span class="token comment" spellcheck="true">// 域信息</span>
  <span class="token keyword">public</span> <span class="token keyword">int</span> a<span class="token punctuation">;</span>
    descriptor<span class="token operator">:</span> I
    flags<span class="token operator">:</span> ACC_PUBLIC
  <span class="token comment" spellcheck="true">// 方法信息</span>
  <span class="token keyword">public</span> cc<span class="token punctuation">.</span>mrbird<span class="token punctuation">.</span>jvm<span class="token punctuation">.</span>learn<span class="token punctuation">.</span><span class="token function">Test</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    descriptor<span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span>V
    flags<span class="token operator">:</span> ACC_PUBLIC
    Code<span class="token operator">:</span>
      stack<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">,</span> locals<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">,</span> args_size<span class="token operator">=</span><span class="token number">1</span>
         <span class="token number">0</span><span class="token operator">:</span> aload_0
         <span class="token number">1</span><span class="token operator">:</span> invokespecial #<span class="token number">1</span>                  <span class="token comment" spellcheck="true">// Method java/lang/Object."&lt;init>":()V</span>
         <span class="token number">4</span><span class="token operator">:</span> aload_0
         <span class="token number">5</span><span class="token operator">:</span> iconst_0
         <span class="token number">6</span><span class="token operator">:</span> putfield      #<span class="token number">2</span>                  <span class="token comment" spellcheck="true">// Field a:I</span>
         <span class="token number">9</span><span class="token operator">:</span> <span class="token keyword">return</span>
      LineNumberTable<span class="token operator">:</span>
        line <span class="token number">5</span><span class="token operator">:</span> <span class="token number">0</span>
        line <span class="token number">9</span><span class="token operator">:</span> <span class="token number">4</span>
      LocalVariableTable<span class="token operator">:</span>
        Start  Length  Slot  Name   Signature
            <span class="token number">0</span>      <span class="token number">10</span>     <span class="token number">0</span>  <span class="token keyword">this</span>   Lcc<span class="token operator">/</span>mrbird<span class="token operator">/</span>jvm<span class="token operator">/</span>learn<span class="token operator">/</span>Test<span class="token punctuation">;</span>
  <span class="token comment" spellcheck="true">// 方法信息</span>
  <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">method1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    descriptor<span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span>V
    flags<span class="token operator">:</span> ACC_PUBLIC
    Code<span class="token operator">:</span>
      <span class="token comment" spellcheck="true">// 操作数栈大小，局部变量表大小，参数个数</span>
      stack<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">,</span> locals<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">,</span> args_size<span class="token operator">=</span><span class="token number">1</span>
         <span class="token number">0</span><span class="token operator">:</span> getstatic     #<span class="token number">3</span>                  <span class="token comment" spellcheck="true">// Field java/lang/System.out:Ljava/io/PrintStream;</span>
         <span class="token number">3</span><span class="token operator">:</span> ldc           #<span class="token number">4</span>                  <span class="token comment" spellcheck="true">// String method1</span>
         <span class="token number">5</span><span class="token operator">:</span> invokevirtual #<span class="token number">5</span>                  <span class="token comment" spellcheck="true">// Method java/io/PrintStream.println:(Ljava/lang/String;)V</span>
         <span class="token number">8</span><span class="token operator">:</span> <span class="token keyword">return</span>
      LineNumberTable<span class="token operator">:</span>
        line <span class="token number">12</span><span class="token operator">:</span> <span class="token number">0</span>
        line <span class="token number">13</span><span class="token operator">:</span> <span class="token number">8</span>
      LocalVariableTable<span class="token operator">:</span>
        Start  Length  Slot  Name   Signature
            <span class="token number">0</span>       <span class="token number">9</span>     <span class="token number">0</span>  <span class="token keyword">this</span>   Lcc<span class="token operator">/</span>mrbird<span class="token operator">/</span>jvm<span class="token operator">/</span>learn<span class="token operator">/</span>Test<span class="token punctuation">;</span>
  <span class="token comment" spellcheck="true">// 方法信息</span>
  <span class="token keyword">public</span> <span class="token keyword">static</span> java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>String <span class="token function">method2</span><span class="token punctuation">(</span>java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>String<span class="token punctuation">)</span><span class="token punctuation">;</span>
    descriptor<span class="token operator">:</span> <span class="token punctuation">(</span>Ljava<span class="token operator">/</span>lang<span class="token operator">/</span>String<span class="token punctuation">;</span><span class="token punctuation">)</span>Ljava<span class="token operator">/</span>lang<span class="token operator">/</span>String<span class="token punctuation">;</span>
    flags<span class="token operator">:</span> ACC_PUBLIC<span class="token punctuation">,</span> ACC_STATIC
    Code<span class="token operator">:</span>
      stack<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">,</span> locals<span class="token operator">=</span><span class="token number">3</span><span class="token punctuation">,</span> args_size<span class="token operator">=</span><span class="token number">1</span>
         <span class="token number">0</span><span class="token operator">:</span> iconst_1
         <span class="token number">1</span><span class="token operator">:</span> istore_1
         <span class="token number">2</span><span class="token operator">:</span> iload_1
         <span class="token number">3</span><span class="token operator">:</span> iconst_0
         <span class="token number">4</span><span class="token operator">:</span> idiv
         <span class="token number">5</span><span class="token operator">:</span> istore_2
         <span class="token number">6</span><span class="token operator">:</span> <span class="token keyword">goto</span>          <span class="token number">14</span>
         <span class="token number">9</span><span class="token operator">:</span> astore_1
        <span class="token number">10</span><span class="token operator">:</span> aload_1
        <span class="token number">11</span><span class="token operator">:</span> invokevirtual #<span class="token number">7</span>                  <span class="token comment" spellcheck="true">// Method java/lang/Exception.printStackTrace:()V</span>
        <span class="token number">14</span><span class="token operator">:</span> aload_0
        <span class="token number">15</span><span class="token operator">:</span> areturn
      <span class="token comment" spellcheck="true">// 异常表</span>
      Exception table<span class="token operator">:</span>
         from    to  target type
             <span class="token number">0</span>     <span class="token number">6</span>     <span class="token number">9</span>   Class <span class="token class-name">java</span><span class="token operator">/</span>lang<span class="token operator">/</span>Exception
      LineNumberTable<span class="token operator">:</span>
        line <span class="token number">17</span><span class="token operator">:</span> <span class="token number">0</span>
        line <span class="token number">18</span><span class="token operator">:</span> <span class="token number">2</span>
        line <span class="token number">21</span><span class="token operator">:</span> <span class="token number">6</span>
        line <span class="token number">19</span><span class="token operator">:</span> <span class="token number">9</span>
        line <span class="token number">20</span><span class="token operator">:</span> <span class="token number">10</span>
        line <span class="token number">22</span><span class="token operator">:</span> <span class="token number">14</span>
      <span class="token comment" spellcheck="true">// 局部变量表</span>
      LocalVariableTable<span class="token operator">:</span>
        Start  Length  Slot  Name   Signature
            <span class="token number">2</span>       <span class="token number">4</span>     <span class="token number">1</span>     a   I
           <span class="token number">10</span>       <span class="token number">4</span>     <span class="token number">1</span>     e   Ljava<span class="token operator">/</span>lang<span class="token operator">/</span>Exception<span class="token punctuation">;</span>
            <span class="token number">0</span>      <span class="token number">16</span>     <span class="token number">0</span>  name   Ljava<span class="token operator">/</span>lang<span class="token operator">/</span>String<span class="token punctuation">;</span>
      StackMapTable<span class="token operator">:</span> number_of_entries <span class="token operator">=</span> <span class="token number">2</span>
        frame_type <span class="token operator">=</span> <span class="token number">73</span> <span class="token comment" spellcheck="true">/* same_locals_1_stack_item */</span>
          stack <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token keyword">class</span> <span class="token class-name">java</span><span class="token operator">/</span>lang<span class="token operator">/</span>Exception <span class="token punctuation">]</span>
        frame_type <span class="token operator">=</span> <span class="token number">4</span> <span class="token comment" spellcheck="true">/* same */</span>

  <span class="token keyword">static</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
    descriptor<span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span>V
    flags<span class="token operator">:</span> ACC_STATIC
    Code<span class="token operator">:</span>
      stack<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">,</span> locals<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">,</span> args_size<span class="token operator">=</span><span class="token number">0</span>
         <span class="token number">0</span><span class="token operator">:</span> ldc           #<span class="token number">8</span>                  <span class="token comment" spellcheck="true">// String hello</span>
         <span class="token number">2</span><span class="token operator">:</span> putstatic     #<span class="token number">9</span>                  <span class="token comment" spellcheck="true">// Field hello:Ljava/lang/String;</span>
         <span class="token number">5</span><span class="token operator">:</span> <span class="token keyword">return</span>
      LineNumberTable<span class="token operator">:</span>
        line <span class="token number">7</span><span class="token operator">:</span> <span class="token number">0</span>
<span class="token punctuation">}</span>
SourceFile<span class="token operator">:</span> <span class="token string">"Test.java"</span>
</code></pre>
<h3 id="方法区的演进"><a href="#方法区的演进" class="headerlink" title="方法区的演进"></a>方法区的演进</h3><p>随着JDK的迭代升级，Hotspot中方法区的存储的内容发生了如下变化（上面介绍的方法区的内部结构是经典情况下的，具体还是需要看JDK是什么版本）：</p>
<table>
<thead>
<tr>
<th align="left">版本</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody><tr>
<td align="left">jdk1.6及之前</td>
<td align="left">有永久代（permanent generation），<strong>静态变量存放在永久代上</strong></td>
</tr>
<tr>
<td align="left">jdk1.7</td>
<td align="left">有永久代，但已经逐步“去永久代”，<strong>字符串常量池、静态变量移除，保存在堆中</strong></td>
</tr>
<tr>
<td align="left">jdk1.8及之后</td>
<td align="left">无永久代，类型信息、字段、方法、<strong>常量</strong>保存在<strong>本地内存的元空间</strong>，但<strong>字符串常量池、静态变量仍然保存在堆中</strong></td>
</tr>
</tbody></table>
<p>上面说的静态变量在JDK1.6之前存放在永久代，JDK1.7后移动到堆空间指的是变量本身，变量对应的对象实例一直都是在堆空间分配的。举个例子：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">StaticObjTest</span> <span class="token punctuation">{</span>

    <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>
        <span class="token keyword">static</span> ObjectHolder staticObj <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ObjectHolder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        ObjectHolder instanceObj <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ObjectHolder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">void</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            ObjectHolder localObj <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ObjectHolder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">ObjectHolder</span> <span class="token punctuation">{</span>

    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>这个例子中，三个new ObjectHolder()的创建，都是在堆中分配的，localObj是方法foo内的局部变量，存放在虚拟机栈的局部变量表中；instanceObj为成员变量，随着对象实例的创建也分配在堆中；静态变量staticObj根据JDK版本的不同存放位置也不同，JDK1.6及之前，存放在永久代中，JDK1.7及之后存放到堆中。</p>
<p>永久代为什么会被元空间替代？因为永久代的大小是很难确定的，如果一个程序动态加载的类过多就很容易触发永久代的Full GC（Full GC代价大，耗时长，影响程序性能）甚至OOM，程序直接奔溃；而元空间和永久代之间最大的区别在于：元空间并不在虚拟机中，而是使用本地内存，这样元空间就基本不会因为触发Full GC和OOM了。</p>
<p>字符串常量池（StringTable）为什么要放到堆中？因为如果将StringTable放在永久代的话回收效率很低，在Full GC的时候才会触发。而Full GC是老年代的空间不足、永久代不足时才会触发。这就导致 StringTable回收效率不高。而我们开发中会有大量的字符串被创建，回收效率低，导致永久代内存不足。放到堆里，能及时回收内存。</p>
<h3 id="方法区垃圾回收"><a href="#方法区垃圾回收" class="headerlink" title="方法区垃圾回收"></a>方法区垃圾回收</h3><p>方法区也存在垃圾回收，方法区的垃圾收集主要回收两部分内容：常量池中废弃的常量和不再使用的类型。</p>
<h2 id="执行引擎"><a href="#执行引擎" class="headerlink" title="执行引擎"></a>执行引擎</h2><p>类加载器加载的字节码并不能够直接运行在操作系统之上，因为字节码指令不是本地机器指令，执行引擎（Execute Engine）的任务就是讲字节码指令解释为对应平台上的本地机器指令。通俗地讲，执行引擎就是将高级语言翻译为本地机器语言的翻译官。</p>
<h3 id="解释器和JIT编译器"><a href="#解释器和JIT编译器" class="headerlink" title="解释器和JIT编译器"></a>解释器和JIT编译器</h3><ul>
<li>解释器（Interpreter）：JVM在程序运行时通过解释器逐行将字节码转为本地机器指令执行；</li>
<li>JIT编译器（Just In Time Compiler，即时编译器）：解释器的优点是程序一启动就可以马上发挥作用，逐行翻译字节码执行程序。而对于一些高频的代码（如循环体内代码和高频调用方法等），如果每次执行都用解释器逐行将字节码翻译为机器指令的话，势必会造成浪费，所以我们可以通过即时编译器将这部分高频代码直接编译为机器指令然后缓存在方法区中（上面介绍方法区内部组成时提到过JIT代码缓存），以此提高执行效率。和解释器相比，即时编译器的缺点就是编译需要耗费一定时间。</li>
</ul>
<p>正因为JVM在执行Java代码的时候，通常会将解释执行和编译执行二者结合起来进行，所以Java也可以说是一种半编译半解释型语言。</p>
<h4 id="热点代码"><a href="#热点代码" class="headerlink" title="热点代码"></a>热点代码</h4><p>hotspot通过两种方式来确定当前代码是否为热点代码：</p>
<ul>
<li>方法调用计数器：统计方法调用的次数；</li>
<li>回边计数器：统计循环体执行的循环次数。</li>
</ul>
<p>当一个方法被调用时，会先检查该方法是否存在被JIT编译器编译过的版本，如果存在，则使用编译后的本地代码执行；如果不存在，则将方法的调用计数器加1，然后判断方法调用计数器和回边计数器之和是否超过方法调用计数器的阈值。如果超过，则会向JIT编译器提交一个该方法的代码编译请求。</p>
<p>上面的阈值可以使用<code>-XX:CompileThreshold</code>设定，默认值在Client模式下是1500，在Server模式下是10000。</p>
<p>方法调用计数器统计的并不是方法被调用的绝对次数，而是在一定时间范围内的次数。超过这个时间范围，这个方法计数器就会减少一半，这个过程称为热度衰减，这个时间周期称为半衰周期。可以通过<code>-XX:CounterHalfLifeTime</code>设置半衰周期（单位S），<code>-XX:-UseCounterDecay</code>来关闭热度衰减。</p>
<h3 id="模式设置"><a href="#模式设置" class="headerlink" title="模式设置"></a>模式设置</h3><p>默认情况下，hotspot采用混合模式架构（即解释器和JIT编译器并存的架构），我们可以通过下面这些指令来切换模式：</p>
<ul>
<li><code>-Xint</code>：完全采用解释器模式执行程序；</li>
<li><code>-Xcomp</code>：完全采用即时编译器模式执行程序，如果即时编译器出现问题，解释器会介入执行；</li>
<li><code>-Xmixed</code>：混合模式。</li>
</ul>
<p><img src="https://mrbird.cc/img/QQ20200706-141640@2x.png" alt="QQ20200706-141640@2x"></p>
<h3 id="JIT编译器分类"><a href="#JIT编译器分类" class="headerlink" title="JIT编译器分类"></a>JIT编译器分类</h3><p>hotspot内置两种JIT编译器：Client Compiler和Server Compiler，也称为C1编译器和C2编译器。我们可以通过下面这些指令来指定使用哪种JIT编译器：</p>
<ul>
<li><code>-client</code>：指定Java虚拟机运行在Client模式下，并使用C1编译器。C1编译器会对字节码进行简单和可靠的优化，耗时短，已达到更快的编译速度；</li>
<li><code>-server</code>：指定Java虚拟机运行在Server模式下，并使用C2编译器。C2编译器进行耗时较长的优化，以及激进优化，虽然编译耗时更长，但代码执行效率更高（64位JDK只支持Server模式）。</li>
</ul>
<blockquote>
<p>参考文章：</p>
</blockquote>
<p><a target="_blank" rel="noopener" href="https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html">https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html</a></p>
<p><a target="_blank" rel="noopener" href="https://docs.oracle.com/en/java/javase/11/tools/java.html">https://docs.oracle.com/en/java/javase/11/tools/java.html</a></p>
<p><a target="_blank" rel="noopener" href="https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html">https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html</a></p>
<p><a target="_blank" rel="noopener" href="http://www.atguigu.com/download_detail.shtml?v=279">http://www.atguigu.com/download_detail.shtml?v=279</a></p>
<p><a target="_blank" rel="noopener" href="https://mrbird.cc/">https://mrbird.cc</a></p>

                
            </div>
            <hr/>

            

    <div class="reprint" id="reprint-statement">
        
            <div class="reprint__author">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-user">
                        文章作者:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="/about" rel="external nofollow noreferrer">八戒取经路</a>
                </span>
            </div>
            <div class="reprint__type">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-link">
                        文章链接:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="https://codejourney.gitee.io/2021/04/22/%E3%80%90JVM%E3%80%91JVM%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">https://codejourney.gitee.io/2021/04/22/%E3%80%90JVM%E3%80%91JVM%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</a>
                </span>
            </div>
            <div class="reprint__notice">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-copyright">
                        版权声明:
                    </i>
                </span>
                <span class="reprint-info">
                    本博客所有文章除特別声明外，均采用
                    <a href="https://creativecommons.org/licenses/by/4.0/deed.zh" rel="external nofollow noreferrer" target="_blank">CC BY 4.0</a>
                    许可协议。转载请注明来源
                    <a href="/about" target="_blank">八戒取经路</a>
                    !
                </span>
            </div>
        
    </div>

    <script async defer>
      document.addEventListener("copy", function (e) {
        let toastHTML = '<span>复制成功，请遵循本文的转载规则</span><button class="btn-flat toast-action" onclick="navToReprintStatement()" style="font-size: smaller">查看</a>';
        M.toast({html: toastHTML})
      });

      function navToReprintStatement() {
        $("html, body").animate({scrollTop: $("#reprint-statement").offset().top - 80}, 800);
      }
    </script>



            <div class="tag_share" style="display: block;">
                <div class="post-meta__tag-list" style="display: inline-block;">
                    
                        <div class="article-tag">
                            
                                <a href="/tags/JVM/">
                                    <span class="chip bg-color">JVM</span>
                                </a>
                            
                        </div>
                    
                </div>
                <div class="post_share" style="zoom: 80%; width: fit-content; display: inline-block; float: right; margin: -0.15rem 0;">
                    <link rel="stylesheet" type="text/css" href="/libs/share/css/share.min.css">
<div id="article-share">

    
    <div class="social-share" data-sites="twitter,facebook,google,qq,qzone,wechat,weibo,douban,linkedin" data-wechat-qrcode-helper="<p>微信扫一扫即可分享！</p>"></div>
    <script src="/libs/share/js/social-share.min.js"></script>
    

    

</div>

                </div>
            </div>
            
                <style>
    #reward {
        margin: 40px 0;
        text-align: center;
    }

    #reward .reward-link {
        font-size: 1.4rem;
        line-height: 38px;
    }

    #reward .btn-floating:hover {
        box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2), 0 5px 15px rgba(0, 0, 0, 0.2);
    }

    #rewardModal {
        width: 320px;
        height: 350px;
    }

    #rewardModal .reward-title {
        margin: 15px auto;
        padding-bottom: 5px;
    }

    #rewardModal .modal-content {
        padding: 10px;
    }

    #rewardModal .close {
        position: absolute;
        right: 15px;
        top: 15px;
        color: rgba(0, 0, 0, 0.5);
        font-size: 1.3rem;
        line-height: 20px;
        cursor: pointer;
    }

    #rewardModal .close:hover {
        color: #ef5350;
        transform: scale(1.3);
        -moz-transform:scale(1.3);
        -webkit-transform:scale(1.3);
        -o-transform:scale(1.3);
    }

    #rewardModal .reward-tabs {
        margin: 0 auto;
        width: 210px;
    }

    .reward-tabs .tabs {
        height: 38px;
        margin: 10px auto;
        padding-left: 0;
    }

    .reward-content ul {
        padding-left: 0 !important;
    }

    .reward-tabs .tabs .tab {
        height: 38px;
        line-height: 38px;
    }

    .reward-tabs .tab a {
        color: #fff;
        background-color: #ccc;
    }

    .reward-tabs .tab a:hover {
        background-color: #ccc;
        color: #fff;
    }

    .reward-tabs .wechat-tab .active {
        color: #fff !important;
        background-color: #22AB38 !important;
    }

    .reward-tabs .alipay-tab .active {
        color: #fff !important;
        background-color: #019FE8 !important;
    }

    .reward-tabs .reward-img {
        width: 210px;
        height: 210px;
    }
</style>

<div id="reward">
    <a href="#rewardModal" class="reward-link modal-trigger btn-floating btn-medium waves-effect waves-light red">赏</a>

    <!-- Modal Structure -->
    <div id="rewardModal" class="modal">
        <div class="modal-content">
            <a class="close modal-close"><i class="fas fa-times"></i></a>
            <h4 class="reward-title">你的赏识是我前进的动力</h4>
            <div class="reward-content">
                <div class="reward-tabs">
                    <ul class="tabs row">
                        <li class="tab col s6 alipay-tab waves-effect waves-light"><a href="#alipay">支付宝</a></li>
                        <li class="tab col s6 wechat-tab waves-effect waves-light"><a href="#wechat">微 信</a></li>
                    </ul>
                    <div id="alipay">
                        <img src="/medias/reward/alipay.jpg" class="reward-img" alt="支付宝打赏二维码">
                    </div>
                    <div id="wechat">
                        <img src="/medias/reward/wechat.png" class="reward-img" alt="微信打赏二维码">
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
    $(function () {
        $('.tabs').tabs();
    });
</script>

            
        </div>
    </div>

    

    

    

    

    

    

    

    

    

<article id="prenext-posts" class="prev-next articles">
    <div class="row article-row">
        
        <div class="article col s12 m6" data-aos="fade-up" data-aos="fade-up">
            <div class="article-badge left-badge text-color">
                <i class="far fa-dot-circle"></i>&nbsp;本篇
            </div>
            <div class="card">
                <a href="/2021/04/22/%E3%80%90JVM%E3%80%91JVM%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">
                    <div class="card-image">
                        
                        
                        <img src="/medias/featureimages/10.jpg" class="responsive-img" alt="【JVM】JVM 学习笔记（第九篇）">
                        
                        <span class="card-title">【JVM】JVM 学习笔记（第九篇）</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            
                        
                    </div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="far fa-clock fa-fw icon-date"></i>2021-04-22
                            </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-user fa-fw"></i>
                            八戒取经路
                            
                        </span>
                    </div>
                </div>

                
                <div class="card-action article-tags">
                    
                    <a href="/tags/JVM/">
                        <span class="chip bg-color">JVM</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge right-badge text-color">
                下一篇&nbsp;<i class="fas fa-chevron-right"></i>
            </div>
            <div class="card">
                <a href="/2021/04/21/%E3%80%90JVM%E3%80%91javap%E4%BD%BF%E7%94%A8%E5%8F%8A%E9%98%85%E8%AF%BB%E5%8F%8D%E6%B1%87%E7%BC%96%E5%90%8E%E7%9A%84%E4%BB%A3%E7%A0%81%EF%BC%88%E7%AC%AC%E5%85%AB%E7%AF%87%EF%BC%89/">
                    <div class="card-image">
                        
                        
                        <img src="/medias/featureimages/1.jpg" class="responsive-img" alt="【JVM】javp使用及阅读反汇编后的字节码（第八篇）">
                        
                        <span class="card-title">【JVM】javp使用及阅读反汇编后的字节码（第八篇）</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            
                        
                    </div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="far fa-clock fa-fw icon-date"></i>2021-04-21
                            </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-user fa-fw"></i>
                            八戒取经路
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/tags/%E5%AD%97%E8%8A%82%E7%A0%81/">
                        <span class="chip bg-color">字节码</span>
                    </a>
                    
                    <a href="/tags/javap/">
                        <span class="chip bg-color">javap</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
    </div>
</article>

</div>



<!-- 代码块功能依赖 -->
<script type="text/javascript" src="/libs/codeBlock/codeBlockFuction.js"></script>

<!-- 代码语言 -->

<script type="text/javascript" src="/libs/codeBlock/codeLang.js"></script>


<!-- 代码块复制 -->

<script type="text/javascript" src="/libs/codeBlock/codeCopy.js"></script>


<!-- 代码块收缩 -->

<script type="text/javascript" src="/libs/codeBlock/codeShrink.js"></script>


    </div>
    <div id="toc-aside" class="expanded col l3 hide-on-med-and-down">
        <div class="toc-widget card" style="background-color: white;">
            <div class="toc-title"><i class="far fa-list-alt"></i>&nbsp;&nbsp;目录</div>
            <div id="toc-content"></div>
        </div>
    </div>
</div>

<!-- TOC 悬浮按钮. -->

<div id="floating-toc-btn" class="hide-on-med-and-down">
    <a class="btn-floating btn-large bg-color">
        <i class="fas fa-list-ul"></i>
    </a>
</div>


<script src="/libs/tocbot/tocbot.min.js"></script>
<script>
    $(function () {
        tocbot.init({
            tocSelector: '#toc-content',
            contentSelector: '#articleContent',
            headingsOffset: -($(window).height() * 0.4 - 45),
            collapseDepth: Number('0'),
            headingSelector: 'h2, h3, h4'
        });

        // modify the toc link href to support Chinese.
        let i = 0;
        let tocHeading = 'toc-heading-';
        $('#toc-content a').each(function () {
            $(this).attr('href', '#' + tocHeading + (++i));
        });

        // modify the heading title id to support Chinese.
        i = 0;
        $('#articleContent').children('h2, h3, h4').each(function () {
            $(this).attr('id', tocHeading + (++i));
        });

        // Set scroll toc fixed.
        let tocHeight = parseInt($(window).height() * 0.4 - 64);
        let $tocWidget = $('.toc-widget');
        $(window).scroll(function () {
            let scroll = $(window).scrollTop();
            /* add post toc fixed. */
            if (scroll > tocHeight) {
                $tocWidget.addClass('toc-fixed');
            } else {
                $tocWidget.removeClass('toc-fixed');
            }
        });

        
        /* 修复文章卡片 div 的宽度. */
        let fixPostCardWidth = function (srcId, targetId) {
            let srcDiv = $('#' + srcId);
            if (srcDiv.length === 0) {
                return;
            }

            let w = srcDiv.width();
            if (w >= 450) {
                w = w + 21;
            } else if (w >= 350 && w < 450) {
                w = w + 18;
            } else if (w >= 300 && w < 350) {
                w = w + 16;
            } else {
                w = w + 14;
            }
            $('#' + targetId).width(w);
        };

        // 切换TOC目录展开收缩的相关操作.
        const expandedClass = 'expanded';
        let $tocAside = $('#toc-aside');
        let $mainContent = $('#main-content');
        $('#floating-toc-btn .btn-floating').click(function () {
            if ($tocAside.hasClass(expandedClass)) {
                $tocAside.removeClass(expandedClass).hide();
                $mainContent.removeClass('l9');
            } else {
                $tocAside.addClass(expandedClass).show();
                $mainContent.addClass('l9');
            }
            fixPostCardWidth('artDetail', 'prenext-posts');
        });
        
    });
</script>

    

</main>




    <footer class="page-footer bg-color">
    
        <link rel="stylesheet" href="/libs/aplayer/APlayer.min.css">
<style>
    .aplayer .aplayer-lrc p {
        
        display: none;
        
        font-size: 12px;
        font-weight: 700;
        line-height: 16px !important;
    }

    .aplayer .aplayer-lrc p.aplayer-lrc-current {
        
        display: none;
        
        font-size: 15px;
        color: #42b983;
    }

    
    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body {
        left: -66px !important;
    }

    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body:hover {
        left: 0px !important;
    }

    
</style>
<div class="">
    
    <div class="row">
        <meting-js class="col l8 offset-l2 m10 offset-m1 s12"
                   server="netease"
                   type="playlist"
                   id="503838841"
                   fixed='true'
                   autoplay='false'
                   theme='#42b983'
                   loop='all'
                   order='random'
                   preload='auto'
                   volume='0.7'
                   list-folded='true'
        >
        </meting-js>
    </div>
</div>

<script src="/libs/aplayer/APlayer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script>

    
    <div class="container row center-align" style="margin-bottom: 0px !important;">
        <div class="col s12 m8 l8 copy-right">
            Copyright&nbsp;&copy;
            
                <span id="year">2019-2021</span>
            
            <span id="year">2019</span>
            <a href="/about" target="_blank">八戒取经路</a>
            |&nbsp;Powered by&nbsp;<a href="https://hexo.io/" target="_blank">Hexo</a>
            |&nbsp;Theme&nbsp;<a href="https://github.com/" target="_blank">Matery</a>
            <br>
            
            
            
            
            
            
            <span id="busuanzi_container_site_pv">
                |&nbsp;<i class="far fa-eye"></i>&nbsp;总访问量:&nbsp;<span id="busuanzi_value_site_pv"
                    class="white-color"></span>&nbsp;次
            </span>
            
            
            <span id="busuanzi_container_site_uv">
                |&nbsp;<i class="fas fa-users"></i>&nbsp;总访问人数:&nbsp;<span id="busuanzi_value_site_uv"
                    class="white-color"></span>&nbsp;人
            </span>
            
            <br>
            
            <br>
            
        </div>
        <div class="col s12 m4 l4 social-link social-statis">
    <a href="https://github.com/blinkfox" class="tooltipped" target="_blank" data-tooltip="访问我的GitHub" data-position="top" data-delay="50">
        <i class="fab fa-github"></i>
    </a>



    <a href="mailto:843355928@qq.com" class="tooltipped" target="_blank" data-tooltip="邮件联系我" data-position="top" data-delay="50">
        <i class="fas fa-envelope-open"></i>
    </a>







    <a href="tencent://AddContact/?fromId=50&fromSubId=1&subcmd=all&uin=843355928" class="tooltipped" target="_blank" data-tooltip="QQ联系我: 843355928" data-position="top" data-delay="50">
        <i class="fab fa-qq"></i>
    </a>







    <a href="/atom.xml" class="tooltipped" target="_blank" data-tooltip="RSS 订阅" data-position="top" data-delay="50">
        <i class="fas fa-rss"></i>
    </a>

</div>
    </div>
</footer>

<div class="progress-bar"></div>


    <!-- 搜索遮罩框 -->
<div id="searchModal" class="modal">
    <div class="modal-content">
        <div class="search-header">
            <span class="title"><i class="fas fa-search"></i>&nbsp;&nbsp;搜索</span>
            <input type="search" id="searchInput" name="s" placeholder="请输入搜索的关键字"
                   class="search-input">
        </div>
        <div id="searchResult"></div>
    </div>
</div>

<script type="text/javascript">
$(function () {
    var searchFunc = function (path, search_id, content_id) {
        'use strict';
        $.ajax({
            url: path,
            dataType: "xml",
            success: function (xmlResponse) {
                // get the contents from search data
                var datas = $("entry", xmlResponse).map(function () {
                    return {
                        title: $("title", this).text(),
                        content: $("content", this).text(),
                        url: $("url", this).text()
                    };
                }).get();
                var $input = document.getElementById(search_id);
                var $resultContent = document.getElementById(content_id);
                $input.addEventListener('input', function () {
                    var str = '<ul class=\"search-result-list\">';
                    var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);
                    $resultContent.innerHTML = "";
                    if (this.value.trim().length <= 0) {
                        return;
                    }
                    // perform local searching
                    datas.forEach(function (data) {
                        var isMatch = true;
                        var data_title = data.title.trim().toLowerCase();
                        var data_content = data.content.trim().replace(/<[^>]+>/g, "").toLowerCase();
                        var data_url = data.url;
                        data_url = data_url.indexOf('/') === 0 ? data.url : '/' + data_url;
                        var index_title = -1;
                        var index_content = -1;
                        var first_occur = -1;
                        // only match artiles with not empty titles and contents
                        if (data_title !== '' && data_content !== '') {
                            keywords.forEach(function (keyword, i) {
                                index_title = data_title.indexOf(keyword);
                                index_content = data_content.indexOf(keyword);
                                if (index_title < 0 && index_content < 0) {
                                    isMatch = false;
                                } else {
                                    if (index_content < 0) {
                                        index_content = 0;
                                    }
                                    if (i === 0) {
                                        first_occur = index_content;
                                    }
                                }
                            });
                        }
                        // show search results
                        if (isMatch) {
                            str += "<li><a href='" + data_url + "' class='search-result-title'>" + data_title + "</a>";
                            var content = data.content.trim().replace(/<[^>]+>/g, "");
                            if (first_occur >= 0) {
                                // cut out 100 characters
                                var start = first_occur - 20;
                                var end = first_occur + 80;
                                if (start < 0) {
                                    start = 0;
                                }
                                if (start === 0) {
                                    end = 100;
                                }
                                if (end > content.length) {
                                    end = content.length;
                                }
                                var match_content = content.substr(start, end);
                                // highlight all keywords
                                keywords.forEach(function (keyword) {
                                    var regS = new RegExp(keyword, "gi");
                                    match_content = match_content.replace(regS, "<em class=\"search-keyword\">" + keyword + "</em>");
                                });

                                str += "<p class=\"search-result\">" + match_content + "...</p>"
                            }
                            str += "</li>";
                        }
                    });
                    str += "</ul>";
                    $resultContent.innerHTML = str;
                });
            }
        });
    };

    searchFunc('/search.xml', 'searchInput', 'searchResult');
});
</script>

    <!-- 回到顶部按钮 -->
<div id="backTop" class="top-scroll">
    <a class="btn-floating btn-large waves-effect waves-light" href="#!">
        <i class="fas fa-arrow-up"></i>
    </a>
</div>


    <script src="/libs/materialize/materialize.min.js"></script>
    <script src="/libs/masonry/masonry.pkgd.min.js"></script>
    <script src="/libs/aos/aos.js"></script>
    <script src="/libs/scrollprogress/scrollProgress.min.js"></script>
    <script src="/libs/lightGallery/js/lightgallery-all.min.js"></script>
    <script src="/js/matery.js"></script>

    <!-- Baidu Analytics -->

    <!-- Baidu Push -->

<script>
    (function () {
        var bp = document.createElement('script');
        var curProtocol = window.location.protocol.split(':')[0];
        if (curProtocol === 'https') {
            bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
        } else {
            bp.src = 'http://push.zhanzhang.baidu.com/push.js';
        }
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(bp, s);
    })();
</script>

    
    <script src="/libs/others/clicklove.js" async="async"></script>
    
    
    <script async src="/libs/others/busuanzi.pure.mini.js"></script>
    

    

    

    <!--腾讯兔小巢-->
    
    

    

    

    
    <script src="/libs/instantpage/instantpage.js" type="module"></script>
    

</body>

</html>
